From 984d7b57b93f50b2d6b472120348e5e6b91abd8a Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 12:44:09 +0100 Subject: [PATCH 01/29] Ignore local Playwright CLI/MCP scratch dirs --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 0d47d6c5..2524bcfc 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ samples/**/.captures/ # Guide screenshot harness: saved Checkly session and raw captures scripts/guides/screenshots/.auth/ scripts/guides/screenshots/output/ + +# Local browser automation scratch +.playwright-cli/ +.playwright-mcp/ From a28304640ad06ffcd380a2f2ae8815ecc03fa34d Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 12:45:01 +0100 Subject: [PATCH 02/29] Bump checkly CLI to 10.0.0 and CI Node to 22 checkly@10 requires Node >=22.13. --- .github/workflows/deploy-checks.yml | 2 +- .github/workflows/preview-checks.yml | 2 +- .github/workflows/static-docs-checks.yml | 2 +- package-lock.json | 1329 ++++++++++++---------- package.json | 2 +- 5 files changed, 750 insertions(+), 587 deletions(-) diff --git a/.github/workflows/deploy-checks.yml b/.github/workflows/deploy-checks.yml index 1b39f70f..6e3590bf 100644 --- a/.github/workflows/deploy-checks.yml +++ b/.github/workflows/deploy-checks.yml @@ -30,7 +30,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'npm' - name: Install dependencies diff --git a/.github/workflows/preview-checks.yml b/.github/workflows/preview-checks.yml index ed5dd5da..37319bd8 100644 --- a/.github/workflows/preview-checks.yml +++ b/.github/workflows/preview-checks.yml @@ -123,7 +123,7 @@ jobs: if: steps.detect.outputs.docs_changed == 'true' && steps.preview.outputs.skipped != 'true' uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'npm' - name: Verify schema-generated API pages on preview diff --git a/.github/workflows/static-docs-checks.yml b/.github/workflows/static-docs-checks.yml index 692db2a4..f63b4d9a 100644 --- a/.github/workflows/static-docs-checks.yml +++ b/.github/workflows/static-docs-checks.yml @@ -56,7 +56,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'npm' - name: Install dependencies diff --git a/package-lock.json b/package-lock.json index ec0e1d74..dd7c1069 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "devDependencies": { "@mintlify/link-rot": "3.0.803", "@playwright/test": "^1.40.0", - "checkly": "8.2.0", + "checkly": "10.0.0", "mint": "4.2.259", "tsx": "^4.23.15", "typescript": "^5.0.0" @@ -154,9 +154,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.10.tgz", + "integrity": "sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==", "dev": true, "license": "MIT", "engines": { @@ -2546,9 +2546,9 @@ } }, "node_modules/@oclif/core": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.11.4.tgz", - "integrity": "sha512-URwiQ5ALx/sJ2iH4vzXEd+H4K6NAI7LRs6Jag3hrgKEpGmaE6alfRC8qjO4GIgb6A3ACaJumqP9twi/M9ywdHQ==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-5.1.9.tgz", + "integrity": "sha512-jZfN6pxHkgDpHD0dk4nhtaUtYdK39oZoWJCfmkpp7CUE+6mUZSb3WDrdBHnxI5n6CJIiWBrLchM7rBvuV0lRSA==", "dev": true, "license": "MIT", "dependencies": { @@ -2557,22 +2557,22 @@ "clean-stack": "^3.0.1", "cli-spinners": "^2.9.2", "debug": "^4.4.3", - "ejs": "^3.1.10", + "ejs": "^6", "get-package-type": "^0.1.0", "indent-string": "^4.0.0", - "is-wsl": "^2.2.0", "lilconfig": "^3.1.3", "minimatch": "^10.2.5", "semver": "^7.8.1", "string-width": "^4.2.3", "supports-color": "^8", - "tinyglobby": "^0.2.16", + "tinyglobby": "^0.2.17", "widest-line": "^3.1.0", "wordwrap": "^1.0.0", - "wrap-ansi": "^7.0.0" + "wrap-ansi": "^7.0.0", + "wsl-utils": "^0.4.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" } }, "node_modules/@oclif/core/node_modules/indent-string": { @@ -2586,9 +2586,9 @@ } }, "node_modules/@oclif/core/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -2599,34 +2599,34 @@ } }, "node_modules/@oclif/plugin-help": { - "version": "6.2.49", - "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-6.2.49.tgz", - "integrity": "sha512-fEsO0YU7ThtzHE1RGuoHxFu/OGlqxm7PCfFp+U1PS8sde4E0cDqjVDuv78+VKrr45LpC5lWOApj7pm3FNfHrVA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-7.0.6.tgz", + "integrity": "sha512-0p9fM8OtQAZi68arvkfvUzbgiVpXGu6fIgkcvTc2wbuIHfDCs6benPU2uxXxfU2yJ0BWJw6cJbCZQN9cK4H6HA==", "dev": true, "license": "MIT", "dependencies": { - "@oclif/core": "^4" + "@oclif/core": "^5.1.9" }, "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" } }, "node_modules/@oclif/plugin-warn-if-update-available": { - "version": "3.1.65", - "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.1.65.tgz", - "integrity": "sha512-HcSJc8SeCVUBHwc063xDL0LcpdjcamAISlisSX14VDDYQayMantvtVNOo9PmciwYpXRXfAykeH1z066YkA9JvQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-4.0.5.tgz", + "integrity": "sha512-zbfnLiYcIOuplVpASnYvMbU7zFbYNO86MDbLNjz2s18ofXcSFaV4U/jx3mBNj6rqW9DMP17UY8mseovdBfRFyA==", "dev": true, "license": "MIT", "dependencies": { - "@oclif/core": "^4", + "@oclif/core": "^5.1.8", "ansis": "^3.17.0", "debug": "^4.4.3", - "http-call": "^5.2.2", "lodash": "^4.18.1", - "registry-auth-token": "^5.1.1" + "registry-auth-token": "^5.1.1", + "undici": "^7.16.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" } }, "node_modules/@oclif/plugin-warn-if-update-available/node_modules/lodash": { @@ -2646,6 +2646,363 @@ "fast-deep-equal": "^3.1.3" } }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.155.0.tgz", + "integrity": "sha512-A6xv7hDtnTm+xlZ7utn6rRQpRMJHRhVr3gjRGqlx0RUX84mNk0pAsy6YN/wWhuOTkaZhRrrzaLxf0NfbH77j2w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.155.0.tgz", + "integrity": "sha512-T1wWwH9/JI5g7Z4kEQwDOwhToxdDhRyOTklH+uuNpJ16m3MZFmGl+l2rKc0NHQdbVRG2LTOBsNjpW3h1BWytPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.155.0.tgz", + "integrity": "sha512-ZoRB3qJxJ8DWA41jHja+YeB0lLfjBy4T+Kr15vnN1k65X3zbJt3rPZftEwN4Ju4tmA4K/T9dWWD7Z8ewQLnrVA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.155.0.tgz", + "integrity": "sha512-vxtL86BtM+IgrpejA86nbTk5j0HKTIMeuaJ1fQciw6p9RfavPtIPjI7gN34owap0yG9txXBaAWpGdxokNwdqIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.155.0.tgz", + "integrity": "sha512-tN6Ru5e0UVnWaIuiH8jEwnvxuxg7FvhWwSd3oe5oDhOD4ObsSr9/N6WfHLjilUWlPPj65ptwrSDH0Y7lzwTzmw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.155.0.tgz", + "integrity": "sha512-h4ozA5n6L6lwolsz9iwunEhKWnIVbmFRots5QxEix0H6nJ5ICpuDa7PuShuhfpIDFe3+Qvyscioyiv+9g+4Syg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.155.0.tgz", + "integrity": "sha512-058/+LardpfuUlsKIvBGk/CYoakEVcMgqYx8GgyUZeOxFWTojYLlCc1Gb60/y21v3esDhHidgiY/Zbq9LpBhaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.155.0.tgz", + "integrity": "sha512-nrOt2Y3xIAzu+lSPzH0864ieO+iCCXgoo9qFlGANE8Xh0cQ+RP8Wstfp+/wXN2YCyb98cAGzX0VruKYw7it/jw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.155.0.tgz", + "integrity": "sha512-KYAayyN5hQbJPtGKtRxlyc8XYmyntOplyXSQzTDrmbz7l/GCrzQbSswvyJFBTH1LGtsZrbXOAfN52i/Kz6kLKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.155.0.tgz", + "integrity": "sha512-CSuSY5hfjtsBnHXydOj8jiNfS1qHbdPZuPz1YL1cSgK7VmNYP+QlZIbG0BBYYBgX/vYEgZwbG9mBdW4YairZ5w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.155.0.tgz", + "integrity": "sha512-7KCfOQm+Nz2N8trAXbQkal4TQ5756WVEmhm35y816YHvyFnEfVsICsiV5k0pEszNf/fRm4cm2i6i18SJ6/iCWg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.155.0.tgz", + "integrity": "sha512-JSlhgoK+/g1TGJI5NuADx2+6syhxnQNLCWLXyO5QLFyetomcr/vIxSdiNlmyAv963YXUzCuwAwRG6npZ5xyJ1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.155.0.tgz", + "integrity": "sha512-WFIX+dPokWp64mi434Md3U3lJaTwNxAphvGjpltoyQjGUsdXavOIRrnp9dOS34Hd75HOAwDxAI+YwWOwqmJbtg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.155.0.tgz", + "integrity": "sha512-g6xSDC/JpbnVOz5uafMGyK3txBVRFMQTx8opv/yHXGxqV3ZMVl3bf7W8XrSnF68dmy3gM4dgReNryuE53+WkeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.155.0.tgz", + "integrity": "sha512-6/4xlxKlZJWrQ0uwDFPc0H9+xLu7068CKhX3vIDW3SbvP/lVgnVuT5v6dyugeWskWpuxqF/WJ4WKwhxjU3pG2w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.155.0.tgz", + "integrity": "sha512-tltklL0J0XjDxIRTBXWOBhvc2mitcmES45pIxhwDWfxRyqz7Vkeu0NekTZEIxGE4f/lXgq3vZcjjffteQOVorg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.155.0.tgz", + "integrity": "sha512-alAb9TzjatUEsOeoncAziUnfdTDxfyswhalFZ9sC6plUgATIUx2NIZ0+bMn6aJ28AduS1OpG/OAisr/YISn4Ig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.155.0.tgz", + "integrity": "sha512-yc5cbSfcGmRv/KpxDFuyk8adEBaWd/9HilWvBbQ4bFbus1V2PUh2mGB2Cfq9rqZTqLeiMT8x0skV+LKp9hOMgQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.155.0.tgz", + "integrity": "sha512-8heq6jGq+rfpTDRDjoQiBHw0maQZf3IXkS99pdHQZPoTL5kyF5qyPS0RidUlSdnWDIqxXb5nux7GBD9cT+imUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz", + "integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, "node_modules/@playwright/test": { "version": "1.54.2", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.2.tgz", @@ -2693,9 +3050,9 @@ "license": "ISC" }, "node_modules/@pnpm/npm-conf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.2.tgz", - "integrity": "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.3.tgz", + "integrity": "sha512-//0sR/cow/s4ICQaYoAobOl4aU8cjU6x/V24V7XkKotb9+O+3zySIYp146vpaobYHnxa4pZX8NkV54Z5AwbDKA==", "dev": true, "license": "MIT", "dependencies": { @@ -3933,9 +4290,9 @@ } }, "node_modules/@types/readable-stream": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.23.tgz", - "integrity": "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==", + "version": "4.0.25", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.25.tgz", + "integrity": "sha512-7GsxL8Wd5X3jh73/qgW7WCnbBvGSdD8U3E4Jiuus3/8I+PN20DtlkJtwFhr/sImXfDDQ2Z03i/9wNiIF3TVSsw==", "dev": true, "license": "MIT", "dependencies": { @@ -3957,9 +4314,9 @@ "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==", "dev": true, "license": "MIT", "dependencies": { @@ -3977,118 +4334,6 @@ "@types/node": "*" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.4.tgz", - "integrity": "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.59.4", - "@typescript-eslint/types": "^8.59.4", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.4.tgz", - "integrity": "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.4.tgz", - "integrity": "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.4.tgz", - "integrity": "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.59.4", - "@typescript-eslint/tsconfig-utils": "8.59.4", - "@typescript-eslint/types": "8.59.4", - "@typescript-eslint/visitor-keys": "8.59.4", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.4.tgz", - "integrity": "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.4", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript/vfs": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.2.tgz", @@ -4137,9 +4382,9 @@ } }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz", + "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==", "dev": true, "license": "MIT", "bin": { @@ -4510,9 +4755,9 @@ } }, "node_modules/ast-types": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", - "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.3.tgz", + "integrity": "sha512-FvWoWYfSCM6kRxCSH+MGLHIKKGRL6A6AW7Zek2O32REPQRdg131428uRTKMBYAeRd3XXAaHDS60Wpri7CdKDrA==", "dev": true, "license": "MIT", "dependencies": { @@ -4607,14 +4852,14 @@ } }, "node_modules/axios": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", - "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.21.0.tgz", + "integrity": "sha512-YCzXMB53Q9PZBsh7yN7wtapit4WepwcHS2fP8QhGsBxSz5YtgYobV7GGlWlAJi+RxfU77GQTQi2DSLUma42EYA==", "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", + "form-data": "^4.0.6", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } @@ -4932,16 +5177,16 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/brace-expansion/node_modules/balanced-match": { @@ -4968,16 +5213,16 @@ } }, "node_modules/broker-factory": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.14.tgz", - "integrity": "sha512-L45k5HMbPIrMid0nTOZ/UPXG/c0aRuQKVrSDFIb1zOkvfiyHgYmIjc3cSiN1KwQIvRDOtKE0tfb3I9EZ3CmpQQ==", + "version": "3.1.15", + "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.15.tgz", + "integrity": "sha512-ko+aWvgNuP49meGrdjUu7rC+Y+Wai3cCPxP3xWwHsHfehFjOh5ZQM2yC4gEB2UddeZ/YXhm0K1eG/L6fxym2Og==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.29.2", + "@babel/runtime": "^7.29.7", "fast-unique-numbers": "^9.0.27", "tslib": "^2.8.1", - "worker-factory": "^7.0.49" + "worker-factory": "^7.0.50" } }, "node_modules/buffer": { @@ -5023,9 +5268,9 @@ "license": "MIT" }, "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.1.tgz", + "integrity": "sha512-DdH81/zPLVS11EUgWq3tEu/xn+EzljlMYooDNdzWEnFha3R3NBMpMV1UqYIpjYHV/SgpFKMIX1Oh7o06SjM/oA==", "dev": true, "license": "MIT", "dependencies": { @@ -5236,59 +5481,72 @@ "license": "MIT" }, "node_modules/checkly": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/checkly/-/checkly-8.2.0.tgz", - "integrity": "sha512-ERQuK2cqvdPrplbTQ/0TcmI2PQDotp2bD7cvNJj6spXPi1NQYcpcDPQlssVKG3eDKLZ5ARxLlSQj28JuSlA0zA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/checkly/-/checkly-10.0.0.tgz", + "integrity": "sha512-fsMxrp+Zn3vgPXKZ+UFTrGu5Lyb6ksGpdKAJqM8BWP4jyojOUABQX3Ca22IEsteyJI7Aoav8v48Q4drmVM5O+w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@oclif/core": "^4.11.3", - "@oclif/plugin-help": "^6.2.49", - "@oclif/plugin-warn-if-update-available": "^3.1.65", - "@typescript-eslint/typescript-estree": "^8.59.4", - "acorn": "^8.16.0", + "@oclif/core": "^5.1.9", + "@oclif/plugin-help": "^7.0.5", + "@oclif/plugin-warn-if-update-available": "^4.0.4", + "acorn": "^8.19.0", "acorn-walk": "^8.3.5", "archiver": "^8.0.0", - "ast-types": "^0.16.1", - "axios": "^1.16.1", - "chalk": "^5.6.2", + "ast-types": "^0.16.3", + "axios": "^1.20.0", + "chalk": "^6.0.1", "ci-info": "^4.4.0", "conf": "^15.1.0", "debug": "^4.4.3", - "dotenv": "^17.4.2", - "execa": "^9.6.1", + "dotenv": "^18.0.8", + "execa": "^10.2.0", "git-repo-info": "^2.1.1", "glob": "^13.0.6", + "http-proxy-agent": "^9.1.0", + "https-proxy-agent": "^9.1.0", "indent-string": "^5.0.0", "jiti": "^2.7.0", - "json-stream-stringify": "^3.1.6", + "json-stream-stringify": "^3.1.7", "json5": "^2.2.3", "jwt-decode": "^4.0.0", "log-symbols": "^7.0.1", "luxon": "^3.7.2", - "minimatch": "^10.2.5", - "mqtt": "^5.15.1", - "open": "^11.0.0", - "p-queue": "^9.3.0", + "minimatch": "^10.2.6", + "mqtt": "^5.16.1", + "open": "^11.0.4", + "oxc-parser": "0.155.0", + "p-queue": "^10.0.0", "prompts": "^2.4.2", "proxy-from-env": "^2.1.0", - "recast": "^0.23.11", - "semver": "^7.8.1", - "string-width": "^8.2.1", - "tunnel": "^0.0.6", - "uuid": "^14.0.0" + "recast": "^0.24.0", + "semver": "^7.8.5", + "socks-proxy-agent": "^10.1.0", + "string-width": "^8.3.0", + "uuid": "^14.0.3", + "yaml": "^2.9.1" }, "bin": { - "checkly": "bin/run" + "checkly": "bin/run.cjs" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=22.13.0" + } + }, + "node_modules/checkly/node_modules/agent-base": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", + "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" } }, "node_modules/checkly/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", "dev": true, "license": "MIT", "engines": { @@ -5298,6 +5556,19 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/checkly/node_modules/chalk": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-6.0.1.tgz", + "integrity": "sha512-/Ce6KNm3vIbWdMlNna6RVIZ/ICQxnJxCicet5LBKK9ZffBkqzDw0xh9EiKSljdRtiIQ1S1z4YgcscUUGzNCWrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/checkly/node_modules/define-lazy-prop": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", @@ -5311,19 +5582,65 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/checkly/node_modules/http-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz", + "integrity": "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/checkly/node_modules/https-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", + "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/checkly/node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/checkly/node_modules/open": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", - "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.4.tgz", + "integrity": "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==", "dev": true, "license": "MIT", "dependencies": { - "default-browser": "^5.4.0", + "default-browser": "^5.5.1", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", - "powershell-utils": "^0.1.0", - "wsl-utils": "^0.3.0" + "powershell-utils": "^0.2.1", + "wsl-utils": "^1.0.0" }, "engines": { "node": ">=20" @@ -5332,6 +5649,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/checkly/node_modules/powershell-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.1.tgz", + "integrity": "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/checkly/node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -5343,9 +5673,9 @@ } }, "node_modules/checkly/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -5355,10 +5685,25 @@ "node": ">=10" } }, + "node_modules/checkly/node_modules/socks-proxy-agent": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-10.1.0.tgz", + "integrity": "sha512-WlMj/67cEJ6MDI1OcsnjuYKDNDoyPCCYZ249kuuXPiMDw9F8PXkVaQ7YWu3siTydfQ/4BEZcvGzu+aYvz7dDCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/checkly/node_modules/string-width": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", - "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", + "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5389,9 +5734,9 @@ } }, "node_modules/checkly/node_modules/uuid": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", - "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.3.tgz", + "integrity": "sha512-Sc5u1VVln93y1Xnz4R+CunOZc7R9LUcTmhj7Rc7Eg3HVcf7rVn2FOoa812fe0W8p3jD7xeoGSYbfqCGGH2B6xw==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -5402,6 +5747,23 @@ "uuid": "dist-node/bin/uuid" } }, + "node_modules/checkly/node_modules/wsl-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.1.tgz", + "integrity": "sha512-c16PKLIRxBYpR3jSWsdS7SFp0COm5SOQdiFjY818dYFHJbMGuLBszpF07LBWmOS1uzrHa9VGdynsEgoeKy0oOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -6063,21 +6425,6 @@ "node": ">=18" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -6270,9 +6617,9 @@ } }, "node_modules/default-browser": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", - "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", "dev": true, "license": "MIT", "dependencies": { @@ -6561,11 +6908,14 @@ } }, "node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "version": "18.0.9", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.9.tgz", + "integrity": "sha512-3fVOW4cB02R066PUSwn8O4TJyz9NckQl7F81blIbaq9jKBm2tSmOKky7ZHIXzGvkVPXCSn6jkpziBPZdGFs8Tw==", "dev": true, "license": "BSD-2-Clause", + "bin": { + "dotenv": "dist/index.cjs" + }, "engines": { "node": ">=12" }, @@ -6596,19 +6946,16 @@ "license": "MIT" }, "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-6.0.1.tgz", + "integrity": "sha512-UaaM14yby8U3k02ihS1Bmj5Kz2d7CCQM1scxpgs4Mhkq8F1wR2gl3+Ts4h5Ne4Mnt7M9m4Dw7jsuMr3+xO4vZA==", "dev": true, "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, "bin": { "ejs": "bin/cli.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.12.18" } }, "node_modules/emoji-regex": { @@ -7064,19 +7411,6 @@ "source-map": "~0.6.1" } }, - "node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -7239,13 +7573,6 @@ "node": ">=6" } }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -7257,27 +7584,27 @@ } }, "node_modules/execa": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", - "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-10.2.1.tgz", + "integrity": "sha512-/Bofl3ZBh2Q4/PG0W63qFzP5vDAypi8Zc90UWTBzaDNIYiX7apPOd0N6L8hG8CojUdq4V51adu8BObP+iVsSTw==", "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.6", "figures": "^6.1.0", - "get-stream": "^9.0.0", + "get-stream": "^9.0.1", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", - "pretty-ms": "^9.2.0", + "pretty-ms": "^9.3.1", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.1.1" + "which-command": "^0.1.0", + "yoctocolors": "^2.2.0" }, "engines": { - "node": "^18.19.0 || >=20.5.0" + "node": ">=22" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" @@ -7521,39 +7848,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/filelist": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", - "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -7641,17 +7935,17 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -8176,9 +8470,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "dev": true, "license": "MIT", "dependencies": { @@ -8588,37 +8882,6 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/http-call": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/http-call/-/http-call-5.3.0.tgz", - "integrity": "sha512-ahwimsC23ICE4kPl9xTBjKB4inbRaeLyZeRunC/1Jy/Z6X8tv22MEAjK+KBOMSVLaqXPTTmd8638waVIKLGx2w==", - "dev": true, - "license": "ISC", - "dependencies": { - "content-type": "^1.0.4", - "debug": "^4.1.1", - "is-retry-allowed": "^1.1.0", - "is-stream": "^2.0.0", - "parse-json": "^4.0.0", - "tunnel-agent": "^0.6.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-call/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -9606,16 +9869,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", @@ -9788,31 +10041,6 @@ "dev": true, "license": "MIT" }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jiti": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", @@ -9823,17 +10051,6 @@ "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9878,13 +10095,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT" - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -9907,9 +10117,9 @@ "license": "BSD-2-Clause" }, "node_modules/json-stream-stringify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", - "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.7.tgz", + "integrity": "sha512-F4MWetLtY42YMaAKw5cV4e47zMD5aOT+tjjQWjX18ACtdkQ5Y/vrcfbcQ107Rh+MXjOCIx4KhW0wPmOvG8iQ5w==", "dev": true, "license": "MIT", "engines": { @@ -11509,13 +11719,13 @@ } }, "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -11609,9 +11819,9 @@ } }, "node_modules/mqtt": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.15.1.tgz", - "integrity": "sha512-V1WnkGuJh3ec9QXzy5Iylw8OOBK+Xu1WhxcQ9mMpLThG+/JZIMV1PgLNRgIiqXhZnvnVLsuyxHl5A/3bHHbcAA==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.16.1.tgz", + "integrity": "sha512-9aEaiR/mLblsMAiynD8quhcGTaINdta2bdyknAtfVzESfoe6Ncdh/uEs5p+3zqcTEtgYErwL4pNk0QkAynXxlg==", "dev": true, "license": "MIT", "dependencies": { @@ -11624,7 +11834,6 @@ "lru-cache": "^10.4.3", "minimist": "^1.2.8", "mqtt-packet": "^9.0.2", - "number-allocator": "^1.0.14", "readable-stream": "^4.7.0", "rfdc": "^1.4.1", "socks": "^2.8.6", @@ -11833,30 +12042,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/number-allocator": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", - "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.1", - "js-sdsl": "4.3.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -12032,6 +12217,43 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oxc-parser": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.155.0.tgz", + "integrity": "sha512-C/ReSf1JUFukK/zvk6jhcNibSssvas5+ktIzK7fbKVd3CedWe59C3QwHEOrEZj/4Rt9+xg0Jeis/Jv1F/KM1mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.155.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/oxc-project" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.155.0", + "@oxc-parser/binding-android-arm64": "0.155.0", + "@oxc-parser/binding-darwin-arm64": "0.155.0", + "@oxc-parser/binding-darwin-x64": "0.155.0", + "@oxc-parser/binding-freebsd-x64": "0.155.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.155.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.155.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.155.0", + "@oxc-parser/binding-linux-arm64-musl": "0.155.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.155.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.155.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.155.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.155.0", + "@oxc-parser/binding-linux-x64-gnu": "0.155.0", + "@oxc-parser/binding-linux-x64-musl": "0.155.0", + "@oxc-parser/binding-openharmony-arm64": "0.155.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.155.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.155.0", + "@oxc-parser/binding-win32-x64-msvc": "0.155.0" + } + }, "node_modules/p-any": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-any/-/p-any-4.0.0.tgz", @@ -12060,17 +12282,13 @@ } }, "node_modules/p-queue": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.0.tgz", - "integrity": "sha512-7NED7xhQ74Ngp4JP/2e0VZHp7vSWfJfqeiR92jPgxsz6m0Se4P03YoTKa9dDXyZ3r6P616gUXttrB6nnHYKang==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-10.0.0.tgz", + "integrity": "sha512-P2wrCri3bhGLPo3kX7qYVXbo/5GvaVATU0DpO24CbeT53Y4z35t8JUWku04ERpXHUYB5rPMi3TkWE3fmJgx5rA==", "dev": true, "license": "MIT", - "dependencies": { - "eventemitter3": "^5.0.4", - "p-timeout": "^7.0.0" - }, "engines": { - "node": ">=20" + "node": ">=22" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -12093,19 +12311,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-timeout": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", - "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/pac-proxy-agent": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", @@ -12180,20 +12385,6 @@ "dev": true, "license": "MIT" }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/parse-latin": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", @@ -12260,13 +12451,16 @@ } }, "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/path-parse": { @@ -12579,9 +12773,9 @@ } }, "node_modules/pretty-ms": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", - "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz", + "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==", "dev": true, "license": "MIT", "dependencies": { @@ -12687,6 +12881,24 @@ "node": ">= 14" } }, + "node_modules/proxy-agent-negotiate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", + "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "kerberos": "^2.0.0" + }, + "peerDependenciesMeta": { + "kerberos": { + "optional": true + } + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -13094,9 +13306,9 @@ } }, "node_modules/recast": { - "version": "0.23.11", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", - "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.24.0.tgz", + "integrity": "sha512-dN08tw9Kl2i8oDBy16NhxBh6qOqsEqmGYpX1xaxPmgz6/6ukopSuysLfvLbieuDMY57jEz6eTmNz6lqH54kuqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13107,7 +13319,7 @@ "tslib": "^2.0.1" }, "engines": { - "node": ">= 4" + "node": ">= 22" } }, "node_modules/recma-build-jsx": { @@ -14079,29 +14291,6 @@ "sharp": "*" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/shiki": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.21.0.tgz", @@ -14914,9 +15103,9 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { @@ -15031,19 +15220,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -15092,29 +15268,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, "node_modules/twoslash": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.6.tgz", @@ -15305,6 +15458,16 @@ "through": "^2.3.8" } }, + "node_modules/undici": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.1.tgz", + "integrity": "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", @@ -15763,22 +15926,6 @@ "dev": true, "license": "MIT" }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/which-boxed-primitive": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", @@ -15853,6 +16000,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-command": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/which-command/-/which-command-0.1.0.tgz", + "integrity": "sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA==", + "dev": true, + "license": "MIT", + "bin": { + "which-command": "cli.js" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/which-command?sponsor=1" + } + }, "node_modules/which-typed-array": { "version": "1.1.19", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", @@ -15896,54 +16059,54 @@ "license": "MIT" }, "node_modules/worker-factory": { - "version": "7.0.49", - "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.49.tgz", - "integrity": "sha512-lW7tpgy6aUv2dFsQhv1yv+XFzdkCf/leoKRTGMPVK5/die6RrUjqgJHJf556qO+ZfytNG6wPXc17E8zzsOLUDw==", + "version": "7.0.50", + "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.50.tgz", + "integrity": "sha512-hhwc0G+sFwM4qBuhJIUBn2p1Jf8v/FwmLUANBf/Q+Lt2uI8mfIZQhXaZQACodQD4R7Zp6cn/6702bIvNn2puJQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.29.2", + "@babel/runtime": "^7.29.7", "fast-unique-numbers": "^9.0.27", "tslib": "^2.8.1" } }, "node_modules/worker-timers": { - "version": "8.0.31", - "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.31.tgz", - "integrity": "sha512-ngkq5S6JuZyztom8tDgBzorLo9byhBMko/sXfgiUD945AuzKGg1GCgDMCC3NaYkicLpGKXutONM36wEX8UbBCA==", + "version": "8.0.34", + "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.34.tgz", + "integrity": "sha512-WXL+Dqsm0G6dnC66rQsvM3tPT2adhbqSirWUCZGglkALOr8ocS0KlpU0iuKbjflJOlu3ydZikMEVrYnHOM9suw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.29.2", + "@babel/runtime": "^7.29.7", "tslib": "^2.8.1", - "worker-timers-broker": "^8.0.16", - "worker-timers-worker": "^9.0.14" + "worker-timers-broker": "^8.0.18", + "worker-timers-worker": "^9.0.15" } }, "node_modules/worker-timers-broker": { - "version": "8.0.16", - "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.16.tgz", - "integrity": "sha512-JyP3AvUGyPGbBGW7XiUewm2+0pN/aYo1QpVf5kdXAfkDZcN3p7NbWrG6XnyDEpDIvfHk/+LCnOW/NsuiU9riYA==", + "version": "8.0.18", + "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.18.tgz", + "integrity": "sha512-FrjzDVX1wKfZN0gRbCFqv8VHuTncG4sbI/WGEg4tSSQeIsnwqg4YBYWMAHYLJtUDEYYmiK65UKFrVMVk2irDSg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.29.2", - "broker-factory": "^3.1.14", + "@babel/runtime": "^7.29.7", + "broker-factory": "^3.1.15", "fast-unique-numbers": "^9.0.27", "tslib": "^2.8.1", - "worker-timers-worker": "^9.0.14" + "worker-timers-worker": "^9.0.15" } }, "node_modules/worker-timers-worker": { - "version": "9.0.14", - "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.14.tgz", - "integrity": "sha512-/qF06C60sXmSLfUl7WglvrDIbspmPOM8UrG63Dnn4bi2x4/DfqHS/+dxF5B+MdHnYO5tVuZYLHdAodrKdabTIg==", + "version": "9.0.15", + "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.15.tgz", + "integrity": "sha512-KKUe7lZ/Aignr51H6hOUik8LwTnIgojH/1lwhli8A8qIEIyewogZTpNpMW5B6BF7nmwBOkUoTYgf1H3QShcjSA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.29.2", + "@babel/runtime": "^7.29.7", "tslib": "^2.8.1", - "worker-factory": "^7.0.49" + "worker-factory": "^7.0.50" } }, "node_modules/wrap-ansi": { @@ -15994,9 +16157,9 @@ } }, "node_modules/wsl-utils": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", - "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.4.0.tgz", + "integrity": "sha512-9YmF+2sFEd+T7TkwlmE337F0IVzfDvDknhtpBQxxXzEOfgPphGlFYpyx0cTuCIFj8/p+sqwBYAeGxOMNSzPPDA==", "dev": true, "license": "MIT", "dependencies": { @@ -16068,9 +16231,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", "dev": true, "license": "ISC", "bin": { @@ -16134,9 +16297,9 @@ } }, "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index d545e1e4..e11ab921 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "devDependencies": { "@mintlify/link-rot": "3.0.803", "@playwright/test": "^1.40.0", - "checkly": "8.2.0", + "checkly": "10.0.0", "mint": "4.2.259", "tsx": "^4.23.15", "typescript": "^5.0.0" From 4ebd6590621d7d354881647cb0fe63ae48955696 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 12:47:20 +0100 Subject: [PATCH 03/29] Typecheck checkly snippets in MDX against the CLI constructs Extracts code blocks that import from checkly, typechecks them with the TypeScript compiler API against the installed CLI, and reports errors at the MDX line. Opt out per block with {/* typecheck-skip */}. Runs report-only in static docs checks for now. --- .github/scripts/typecheck-snippets.mjs | 134 ++++++++++++++++++++ .github/scripts/typecheck-snippets.test.mjs | 130 +++++++++++++++++++ .github/workflows/static-docs-checks.yml | 21 ++- package-lock.json | 15 ++- package.json | 3 + 5 files changed, 295 insertions(+), 8 deletions(-) create mode 100644 .github/scripts/typecheck-snippets.mjs create mode 100644 .github/scripts/typecheck-snippets.test.mjs diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs new file mode 100644 index 00000000..56b3c266 --- /dev/null +++ b/.github/scripts/typecheck-snippets.mjs @@ -0,0 +1,134 @@ +// Typechecks MDX code snippets that import from `checkly` against the +// installed Checkly CLI constructs, so docs examples don't drift from the CLI. +// +// Only complete snippets (ones with a `checkly` import) are checked. Opt a +// block out by putting `{/* typecheck-skip */}` on the line before its fence. +// +// Usage: node .github/scripts/typecheck-snippets.mjs [root] +import { readdirSync, readFileSync, existsSync } from 'node:fs'; +import { dirname, join, relative, sep } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import ts from 'typescript'; + +const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..'); +const SKIP_MARKER = '{/* typecheck-skip */}'; +const LANGS = { ts: 'ts', typescript: 'ts', js: 'js', javascript: 'js' }; +const CHECKLY_IMPORT = /from\s+['"]checkly(\/[\w-]+)?['"]/; + +export function extractSnippets(mdx, file) { + const lines = mdx.split('\n'); + const snippets = []; + let open = null; + + lines.forEach((text, i) => { + if (!open) { + const match = text.match(/^(\s*)```(\S*)/); + if (!match) return; + let prev = i - 1; + while (prev >= 0 && lines[prev].trim() === '') prev--; + open = { indent: match[1].length, ext: LANGS[match[2]], start: i + 1, body: [], skip: prev >= 0 && lines[prev].trim() === SKIP_MARKER }; + return; + } + if (/^\s*```\s*$/.test(text)) { + const code = open.body.join('\n'); + if (open.ext && !open.skip && CHECKLY_IMPORT.test(code)) { + snippets.push({ file, line: open.start + 1, ext: open.ext, code }); + } + open = null; + return; + } + open.body.push(text.slice(Math.min(open.indent, text.length - text.trimStart().length))); + }); + + return snippets; +} + +const compilerOptions = { + target: ts.ScriptTarget.ES2022, + module: ts.ModuleKind.ESNext, + moduleResolution: ts.ModuleResolutionKind.Bundler, + allowJs: true, + checkJs: true, + skipLibCheck: true, + noEmit: true, + types: ['node'], +}; + +// Multi-file examples import siblings like `./group.check`. Those can't +// resolve here; the imports become `any`, which keeps the `checkly` usage checked. +const isUnresolvedRelativeImport = d => d.code === 2307 && /module '\.\.?\//.test(ts.flattenDiagnosticMessageText(d.messageText, '\n')); + +export function typecheckSnippets(snippets) { + const virtual = new Map(snippets.map((s, i) => [join(repoRoot, '.snippets', `${i}.${s.ext}`).split(sep).join('/'), s])); + const host = ts.createCompilerHost(compilerOptions); + const { getSourceFile, fileExists, readFile } = host; + host.fileExists = f => virtual.has(f) || fileExists(f); + host.readFile = f => virtual.get(f)?.code ?? readFile(f); + host.getSourceFile = (f, lang, ...rest) => virtual.has(f) + ? ts.createSourceFile(f, virtual.get(f).code, lang, true) + : getSourceFile(f, lang, ...rest); + + const program = ts.createProgram([...virtual.keys()], compilerOptions, host); + const errors = []; + + for (const [path, snippet] of virtual) { + const source = program.getSourceFile(path); + const syntactic = program.getSyntacticDiagnostics(source); + // Type errors on code that doesn't parse are noise; report the parse errors only. + const diagnostics = syntactic.length > 0 ? syntactic : program.getSemanticDiagnostics(source).filter(d => !isUnresolvedRelativeImport(d)); + for (const d of diagnostics) { + const { line, character } = source.getLineAndCharacterOfPosition(d.start ?? 0); + errors.push({ + file: snippet.file, + line: snippet.line + line, + column: character + 1, + message: `TS${d.code}: ${ts.flattenDiagnosticMessageText(d.messageText, '\n')}`, + }); + } + } + + return errors; +} + +function mdxFiles(root) { + const ignoredDirs = ['node_modules', 'samples', '.git']; + const mintignore = join(root, '.mintignore'); + if (existsSync(mintignore)) { + for (const entry of readFileSync(mintignore, 'utf8').split('\n')) { + const dir = entry.trim().match(/^([^*#][^*]*?)\/\*\*/)?.[1]; + if (dir) ignoredDirs.push(dir); + } + } + + const files = []; + const walk = dir => { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { + if (!ignoredDirs.includes(relative(root, path).split(sep).join('/'))) walk(path); + } else if (entry.name.endsWith('.mdx')) { + files.push(path); + } + } + }; + walk(root); + return files; +} + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const root = process.argv[2] ?? process.cwd(); + const snippets = mdxFiles(root).flatMap(path => extractSnippets(readFileSync(path, 'utf8'), relative(root, path).split(sep).join('/'))); + const errors = typecheckSnippets(snippets); + + for (const e of errors) { + if (process.env.GITHUB_ACTIONS) { + console.log(`::error file=${e.file},line=${e.line},col=${e.column}::${e.message.replace(/\n/g, '%0A')}`); + } else { + console.error(`${e.file}:${e.line}:${e.column} - ${e.message}`); + } + } + + const checklyVersion = JSON.parse(readFileSync(join(repoRoot, 'node_modules/checkly/package.json'), 'utf8')).version; + console.log(`Typechecked ${snippets.length} snippets against checkly@${checklyVersion}: ${errors.length} error(s).`); + if (errors.length > 0) process.exitCode = 1; +} diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs new file mode 100644 index 00000000..3d051eed --- /dev/null +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -0,0 +1,130 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { extractSnippets, typecheckSnippets } from './typecheck-snippets.mjs'; + +const fence = '```'; + +test('extracts only code blocks that import from checkly, with their MDX start line', () => { + const mdx = [ + '---', + 'title: Test', + '---', + '', + `${fence}ts api.check.ts`, + `import { ApiCheck } from 'checkly/constructs'`, + `new ApiCheck('a', { name: 'A', request: { method: 'GET', url: 'https://x.dev' } })`, + fence, + '', + `${fence}ts`, + `request: { method: 'GET' }`, + fence, + '', + `${fence}bash`, + `npx checkly test`, + fence, + ].join('\n'); + + const snippets = extractSnippets(mdx, 'constructs/api-check.mdx'); + + assert.equal(snippets.length, 1); + assert.equal(snippets[0].file, 'constructs/api-check.mdx'); + assert.equal(snippets[0].line, 6); + assert.equal(snippets[0].ext, 'ts'); + assert.match(snippets[0].code, /^import \{ ApiCheck \}/); +}); + +test('strips fence indentation and maps js fences to .js', () => { + const mdx = [ + '', + ' ', + ` ${fence}javascript`, + ` const { ApiCheck } = {}`, + ` import { Frequency } from "checkly/constructs"`, + ` ${fence}`, + ' ', + '', + ].join('\n'); + + const [snippet] = extractSnippets(mdx, 'page.mdx'); + + assert.equal(snippet.ext, 'js'); + assert.equal(snippet.line, 4); + assert.equal(snippet.code, 'const { ApiCheck } = {}\nimport { Frequency } from "checkly/constructs"'); +}); + +test('skips a block preceded by a typecheck-skip comment', () => { + const mdx = [ + '{/* typecheck-skip */}', + `${fence}ts`, + `import { ApiCheck } from 'checkly/constructs'`, + fence, + '', + `${fence}ts`, + `import { ApiCheck } from 'checkly/constructs'`, + fence, + ].join('\n'); + + const snippets = extractSnippets(mdx, 'page.mdx'); + + assert.equal(snippets.length, 1); + assert.equal(snippets[0].line, 7); +}); + +function snippet(code, line = 10) { + return { file: 'page.mdx', line, ext: 'ts', code }; +} + +test('reports no errors for a valid construct', () => { + const errors = typecheckSnippets([snippet([ + `import { ApiCheck, AssertionBuilder } from 'checkly/constructs'`, + `new ApiCheck('a', {`, + ` name: 'A',`, + ` request: { method: 'GET', url: 'https://x.dev', assertions: [AssertionBuilder.statusCode().equals(200)] },`, + `})`, + ].join('\n'))]); + + assert.deepEqual(errors, []); +}); + +test('reports a construct API mismatch at the MDX line', () => { + const errors = typecheckSnippets([snippet([ + `import { ApiCheck } from 'checkly/constructs'`, + `new ApiCheck('a', {`, + ` name: 'A',`, + ` doesNotExist: true,`, + ` request: { method: 'GET', url: 'https://x.dev' },`, + `})`, + ].join('\n'))]); + + assert.equal(errors.length, 1); + assert.equal(errors[0].file, 'page.mdx'); + assert.equal(errors[0].line, 13); + assert.match(errors[0].message, /doesNotExist/); +}); + +test('reports a missing construct export', () => { + const errors = typecheckSnippets([snippet(`import { NotAConstruct } from 'checkly/constructs'`)]); + + assert.equal(errors.length, 1); + assert.match(errors[0].message, /NotAConstruct/); +}); + +test('ignores unresolvable relative imports from multi-file examples', () => { + const errors = typecheckSnippets([snippet([ + `import { ApiCheck } from 'checkly/constructs'`, + `import { group } from './group.check'`, + `new ApiCheck('a', { name: 'A', group, request: { method: 'GET', url: 'https://x.dev' } })`, + ].join('\n'))]); + + assert.deepEqual(errors, []); +}); + +test('reports syntax errors without hiding type errors in other snippets', () => { + const errors = typecheckSnippets([ + snippet(`import { ApiCheck } from 'checkly/constructs'\nnew ApiCheck('a', {\n ...\n})`, 10), + snippet(`import { NotAConstruct } from 'checkly/constructs'`, 50), + ]); + + // TypeScript reports the bare `...` at the next token, the closing `}`. + assert.deepEqual(errors.map(e => e.line), [13, 50]); +}); diff --git a/.github/workflows/static-docs-checks.yml b/.github/workflows/static-docs-checks.yml index f63b4d9a..bd3dc8e0 100644 --- a/.github/workflows/static-docs-checks.yml +++ b/.github/workflows/static-docs-checks.yml @@ -45,6 +45,14 @@ jobs: echo "openapi_changed=false" >> "$GITHUB_OUTPUT" fi + # A checkly CLI bump or a change to the snippet checker re-runs the + # snippet typecheck even when no docs changed. + if echo "$CHANGED" | grep -qE '^(package(-lock)?\.json|\.github/scripts/typecheck-snippets(\.test)?\.mjs)$'; then + echo "snippets_tooling_changed=true" >> "$GITHUB_OUTPUT" + else + echo "snippets_tooling_changed=false" >> "$GITHUB_OUTPUT" + fi + # Same docs-detection regex as docs-gate / preview-checks NON_DOCS_RE='^(\.github/|.*\.sh$|[^/]+\.md$|package(-lock)?\.json$|node_modules/|checkly\.config\.ts$|block-headless\.js$|__checks__/)' if echo "$CHANGED" | grep -vE "$NON_DOCS_RE" | grep -q .; then @@ -60,7 +68,7 @@ jobs: cache: 'npm' - name: Install dependencies - if: steps.detect.outputs.openapi_changed == 'true' || steps.detect.outputs.docs_changed == 'true' + if: steps.detect.outputs.openapi_changed == 'true' || steps.detect.outputs.docs_changed == 'true' || steps.detect.outputs.snippets_tooling_changed == 'true' run: npm ci - name: Validate OpenAPI spec @@ -70,6 +78,17 @@ jobs: - name: Test API navigation tooling run: npm run test:api-docs + # Typechecks MDX snippets that import from `checkly` against the + # installed CLI constructs, so examples don't drift from the CLI API. + # Errors show up as inline annotations on the PR. Report-only until the + # existing failures are fixed; then drop continue-on-error. + - name: Typecheck checkly snippets + if: steps.detect.outputs.docs_changed == 'true' || steps.detect.outputs.snippets_tooling_changed == 'true' + continue-on-error: true + run: | + npm run test:snippets + npm run check:snippets + - name: Check API group badges match the schema run: npm run sync:api-group-tags -- --check diff --git a/package-lock.json b/package-lock.json index dd7c1069..60b6aa81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "devDependencies": { "@mintlify/link-rot": "3.0.803", "@playwright/test": "^1.40.0", + "@types/node": "22.20.5", "checkly": "10.0.0", "mint": "4.2.259", "tsx": "^4.23.15", @@ -4269,13 +4270,13 @@ } }, "node_modules/@types/node": { - "version": "24.2.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz", - "integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==", + "version": "22.20.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.5.tgz", + "integrity": "sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.10.0" + "undici-types": "~6.21.0" } }, "node_modules/@types/react": { @@ -15469,9 +15470,9 @@ } }, "node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index e11ab921..88042eda 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "dev": "mint dev", "test:api-docs": "node --test .github/scripts/api-navigation.test.mjs", "check:links": "node .github/scripts/check-broken-links.mjs", + "check:snippets": "node .github/scripts/typecheck-snippets.mjs", + "test:snippets": "node --test .github/scripts/typecheck-snippets.test.mjs", "sync:api-group-tags": "node .github/scripts/sync-api-group-tags.mjs", "deploy": "checkly deploy", "test": "checkly test", @@ -19,6 +21,7 @@ "devDependencies": { "@mintlify/link-rot": "3.0.803", "@playwright/test": "^1.40.0", + "@types/node": "22.20.5", "checkly": "10.0.0", "mint": "4.2.259", "tsx": "^4.23.15", From ca7b75af0e17c7b0e74de2c23d38c297bbc04672 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 12:48:26 +0100 Subject: [PATCH 04/29] Make defineConfig and runtime snippets typecheck against checkly@10 Add required projectName/logicalId to abbreviated config examples, close the unterminated ApiCheck example and give it a request, and shift highlight ranges accordingly. --- cli/checkly-runtimes.mdx | 5 ++++- .../playwright-checks/configuration.mdx | 15 +++++++++++---- .../playwright-checks/custom-dependencies.mdx | 8 +++++++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/cli/checkly-runtimes.mdx b/cli/checkly-runtimes.mdx index b1c8dade..971ef585 100644 --- a/cli/checkly-runtimes.mdx +++ b/cli/checkly-runtimes.mdx @@ -61,11 +61,12 @@ Common packages included in Checkly runtimes: Specify a runtime version in your `checkly.config.ts`: -```typescript checkly.config.ts highlight={6} +```typescript checkly.config.ts highlight={7} import { defineConfig } from 'checkly' export default defineConfig({ projectName: 'My Project', + logicalId: 'my-project', checks: { runtimeId: '2025.04', } @@ -81,7 +82,9 @@ import { ApiCheck } from 'checkly/constructs' new ApiCheck('books-api-check-2', { name: 'Books API', runtimeId: '2025.04', + request: { method: 'GET', url: 'https://danube-web.shop/api/books' }, /* More options... */ +}) ``` Or in your check groups: diff --git a/detect/synthetic-monitoring/playwright-checks/configuration.mdx b/detect/synthetic-monitoring/playwright-checks/configuration.mdx index e33f770f..37e5d967 100644 --- a/detect/synthetic-monitoring/playwright-checks/configuration.mdx +++ b/detect/synthetic-monitoring/playwright-checks/configuration.mdx @@ -15,12 +15,13 @@ Use the `checkly.config.ts/js` file to define your Playwright Check Suite. Each To add Playwright Check Suites to your Checkly monitoring setup, specify the path to your `playwright.config.ts/js` and add a new `playwrightChecks` property to the existing `checks` configuration in your `checkly.config.ts/js`. -```typescript checkly.config.ts highlight={8-14} +```typescript checkly.config.ts highlight={9-15} import { defineConfig } from 'checkly' import { Frequency } from 'checkly/constructs' export default defineConfig({ - // ... + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: './playwright.config.ts', @@ -195,6 +196,8 @@ import { Frequency } from 'checkly/constructs' import { productionGroup } from './production-group.check' export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', // Shared Checkly configuration (scheduling, locations, etc.) // ... checks: { @@ -287,10 +290,12 @@ Specify this option in your `playwright.config` or the `testCommand` in your `ch ``` - ```typescript checkly.config.ts highlight={11} + ```typescript checkly.config.ts highlight={13} import { defineConfig } from 'checkly' export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: './playwright.config.ts', playwrightChecks: [ @@ -324,10 +329,12 @@ Specify this option in your `playwright.config` or the `testCommand` in your `ch ``` - ```typescript checkly.config.ts highlight={11} + ```typescript checkly.config.ts highlight={13} import { defineConfig } from 'checkly' export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: './playwright.config.ts', playwrightChecks: [ diff --git a/detect/synthetic-monitoring/playwright-checks/custom-dependencies.mdx b/detect/synthetic-monitoring/playwright-checks/custom-dependencies.mdx index 31c61aff..30887432 100644 --- a/detect/synthetic-monitoring/playwright-checks/custom-dependencies.mdx +++ b/detect/synthetic-monitoring/playwright-checks/custom-dependencies.mdx @@ -127,10 +127,12 @@ Add your `.npmrc` file to the `checks.include` property in your `checkly.config. When you run `npx checkly test` or `npx checkly deploy`, the CLI bundles and uploads these files. This makes them available when Checkly runs `installCommand` to install your dependencies. -```typescript checkly.config.ts highlight={6} +```typescript checkly.config.ts highlight={10} import { defineConfig } from 'checkly' export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: './playwright.config.ts', // Include .npmrc for authentication with private registries @@ -154,6 +156,8 @@ If you're confident your dependencies work without lifecycle scripts, you can us import { defineConfig } from 'checkly' export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightChecks: [ { @@ -172,6 +176,8 @@ If a dependency does require its install hooks to function correctly, use the [` import { defineConfig } from 'checkly' export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { include: ['scripts/**/*', 'config/**/*'], playwrightChecks: [ From 2eb930abd9d9e8c3ae5be6477e5a0b00ddfdc722 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 12:49:58 +0100 Subject: [PATCH 05/29] Add missing construct imports to snippets; allow partial usage snippets Snippets marked with /* More options... */ may omit required props; wrong or unknown props still fail the typecheck. --- .github/scripts/typecheck-snippets.mjs | 16 ++++++++++--- .github/scripts/typecheck-snippets.test.mjs | 25 +++++++++++++++++++++ constructs/browser-check.mdx | 9 ++++++-- constructs/check-group-v2.mdx | 2 +- constructs/check-group.mdx | 2 +- constructs/multistep-check.mdx | 2 +- constructs/playwright-check.mdx | 4 +++- constructs/tcp-monitor.mdx | 2 +- 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index 56b3c266..6f9f5649 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -1,8 +1,9 @@ // Typechecks MDX code snippets that import from `checkly` against the // installed Checkly CLI constructs, so docs examples don't drift from the CLI. // -// Only complete snippets (ones with a `checkly` import) are checked. Opt a -// block out by putting `{/* typecheck-skip */}` on the line before its fence. +// Only complete snippets (ones with a `checkly` import) are checked. Snippets +// with a `/* More options... */` comment may omit required props. Opt a block +// out by putting `{/* typecheck-skip */}` on the line before its fence. // // Usage: node .github/scripts/typecheck-snippets.mjs [root] import { readdirSync, readFileSync, existsSync } from 'node:fs'; @@ -58,6 +59,13 @@ const compilerOptions = { // resolve here; the imports become `any`, which keeps the `checkly` usage checked. const isUnresolvedRelativeImport = d => d.code === 2307 && /module '\.\.?\//.test(ts.flattenDiagnosticMessageText(d.messageText, '\n')); +// Usage snippets mark omitted props with `/* More options... */`. In those, +// a missing required prop is intended; wrong or unknown props still fail. +const PARTIAL_MARKER = /\/\*\s*More options/i; +const MISSING_PROPS = new Set([2739, 2740, 2741]); +const isOnlyMissingProps = d => d.code === 2345 && typeof d.messageText === 'object' + && d.messageText.next?.length > 0 && d.messageText.next.every(n => MISSING_PROPS.has(n.code)); + export function typecheckSnippets(snippets) { const virtual = new Map(snippets.map((s, i) => [join(repoRoot, '.snippets', `${i}.${s.ext}`).split(sep).join('/'), s])); const host = ts.createCompilerHost(compilerOptions); @@ -75,7 +83,9 @@ export function typecheckSnippets(snippets) { const source = program.getSourceFile(path); const syntactic = program.getSyntacticDiagnostics(source); // Type errors on code that doesn't parse are noise; report the parse errors only. - const diagnostics = syntactic.length > 0 ? syntactic : program.getSemanticDiagnostics(source).filter(d => !isUnresolvedRelativeImport(d)); + const partial = PARTIAL_MARKER.test(snippet.code); + const diagnostics = syntactic.length > 0 ? syntactic : program.getSemanticDiagnostics(source) + .filter(d => !isUnresolvedRelativeImport(d) && !(partial && isOnlyMissingProps(d))); for (const d of diagnostics) { const { line, character } = source.getLineAndCharacterOfPosition(d.start ?? 0); errors.push({ diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index 3d051eed..ea8fd3b0 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -119,6 +119,31 @@ test('ignores unresolvable relative imports from multi-file examples', () => { assert.deepEqual(errors, []); }); +test('allows missing required props in snippets marked with a "More options" comment', () => { + const errors = typecheckSnippets([ + snippet(`import { BrowserCheck, Frequency } from 'checkly/constructs'\nnew BrowserCheck('a', {\n frequency: Frequency.EVERY_5M,\n /* More options... */\n})`), + snippet(`import { TcpMonitor } from 'checkly/constructs'\nnew TcpMonitor('a', {\n /* More options ... */\n})`), + ]); + + assert.deepEqual(errors, []); +}); + +test('still reports wrong props in snippets marked with a "More options" comment', () => { + const errors = typecheckSnippets([ + snippet(`import { BrowserCheck } from 'checkly/constructs'\nnew BrowserCheck('a', {\n frequency: 'often',\n /* More options... */\n})`), + snippet(`import { BrowserCheck } from 'checkly/constructs'\nnew BrowserCheck('a', {\n doesNotExist: true,\n /* More options... */\n})`, 50), + ]); + + assert.deepEqual(errors.map(e => e.line), [12, 52]); +}); + +test('reports missing required props in complete snippets', () => { + const errors = typecheckSnippets([snippet(`import { BrowserCheck } from 'checkly/constructs'\nnew BrowserCheck('a', { name: 'A' })`)]); + + assert.equal(errors.length, 1); + assert.match(errors[0].message, /'code' is missing/); +}); + test('reports syntax errors without hiding type errors in other snippets', () => { const errors = typecheckSnippets([ snippet(`import { ApiCheck } from 'checkly/constructs'\nnew ApiCheck('a', {\n ...\n})`, 10), diff --git a/constructs/browser-check.mdx b/constructs/browser-check.mdx index 4af95d93..738b4887 100644 --- a/constructs/browser-check.mdx +++ b/constructs/browser-check.mdx @@ -172,7 +172,9 @@ new BrowserCheck("quick-test", { ``` ```ts Complex Test File +import { BrowserCheck } from "checkly/constructs" import { secret } from "checkly/util" +import * as path from "path" new BrowserCheck("e2e-purchase", { name: "E-commerce Purchase Flow", @@ -213,7 +215,7 @@ How often the Browser Check should run. Use the `Frequency` enum to set the chec **Usage:** ```ts highlight={5} -import { Frequency } from 'checkly/constructs' +import { BrowserCheck, Frequency } from 'checkly/constructs' new BrowserCheck("my-check", { name: "My Browser Check", @@ -386,7 +388,8 @@ Check-level environment variables that will be available during test execution. **Usage:** -```ts highlight={5-8} +```ts highlight={6-9} +import { BrowserCheck } from "checkly/constructs" import { secret } from "checkly/util" new BrowserCheck("my-check", { @@ -412,7 +415,9 @@ new BrowserCheck("my-check", { ```ts Test Credentials +import { BrowserCheck } from "checkly/constructs" import { secret } from "checkly/util" +import * as path from "path" new BrowserCheck("user-flow", { name: "User Account Flow", diff --git a/constructs/check-group-v2.mdx b/constructs/check-group-v2.mdx index 9eb56e5f..330b29d5 100644 --- a/constructs/check-group-v2.mdx +++ b/constructs/check-group-v2.mdx @@ -158,7 +158,7 @@ How often to run checks within the group. Checks in your project that don't set **Usage:** ```ts highlight={5} -import { Frequency } from 'checkly/constructs' +import { CheckGroupV2, Frequency } from 'checkly/constructs' const group = new CheckGroupV2('api-monitoring-group', { name: "API Monitoring Group", diff --git a/constructs/check-group.mdx b/constructs/check-group.mdx index 8dc2a81d..7ff424f2 100644 --- a/constructs/check-group.mdx +++ b/constructs/check-group.mdx @@ -159,7 +159,7 @@ How often to run checks within the group. This frequency applies to all checks i **Usage:** ```ts highlight={5} -import { Frequency } from 'checkly/constructs' +import { CheckGroup, Frequency } from 'checkly/constructs' const group = new CheckGroup("api-monitoring-group", { name: "API Monitoring Group", diff --git a/constructs/multistep-check.mdx b/constructs/multistep-check.mdx index 42f3896c..728836b9 100644 --- a/constructs/multistep-check.mdx +++ b/constructs/multistep-check.mdx @@ -301,7 +301,7 @@ How often the multistep check should run. Use the `Frequency` enum to set the ch Usage: ```ts highlight={5} -import { Frequency } from 'checkly/constructs' +import { Frequency, MultiStepCheck } from 'checkly/constructs' new MultiStepCheck("my-multistep", { name: "My Multistep Check", diff --git a/constructs/playwright-check.mdx b/constructs/playwright-check.mdx index 332ccc78..8500c761 100644 --- a/constructs/playwright-check.mdx +++ b/constructs/playwright-check.mdx @@ -467,7 +467,8 @@ Check-level environment variables that will be available during test execution. **Usage:** -```ts highlight={6-9} +```ts highlight={7-10} +import { PlaywrightCheck } from "checkly/constructs" import { secret } from "checkly/util" new PlaywrightCheck("user-flow-pwt-check-suite", { @@ -493,6 +494,7 @@ new PlaywrightCheck("user-flow-pwt-check-suite", { ```ts Test Credentials +import { PlaywrightCheck } from "checkly/constructs" import { secret } from "checkly/util" new PlaywrightCheck("user-flow-pwt-check-suite", { diff --git a/constructs/tcp-monitor.mdx b/constructs/tcp-monitor.mdx index 03572834..895b5bbc 100644 --- a/constructs/tcp-monitor.mdx +++ b/constructs/tcp-monitor.mdx @@ -302,7 +302,7 @@ How often the TCP monitor should run. Use the `Frequency` enum to set the check Usage: ```ts highlight={4} -import { Frequency } from 'checkly/constructs' +import { Frequency, TcpMonitor } from 'checkly/constructs' new TcpMonitor("my-monitor", { frequency: Frequency.EVERY_2M, From 66975dc23791aa4133e504d589333af41dfb64d1 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 12:50:04 +0100 Subject: [PATCH 06/29] Use the More options placeholder instead of invalid ... in importing example --- cli/importing.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/importing.mdx b/cli/importing.mdx index b005c3c2..eb62394c 100644 --- a/cli/importing.mdx +++ b/cli/importing.mdx @@ -73,12 +73,12 @@ new BrowserCheck('check-landing-page-3eNrQgOb', { code: { entrypoint: './check-landing-page.spec.ts', }, - ... + /* More options... */ alertChannels: [ // Note the usage of the imported alert channel here emailAlert1, ], - ... + /* More options... */ }) ``` From 75b24ede791ce1ce3569bbf46605491e95b31f5d Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 12:54:04 +0100 Subject: [PATCH 07/29] Skip typecheck for CLI v9-only AgenticCheck snippets AgenticCheck was removed in checkly@10; these pages document v9 until the December 1, 2026 shutdown. --- constructs/agentic-check.mdx | 3 +++ detect/synthetic-monitoring/agentic-checks/configuration.mdx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/constructs/agentic-check.mdx b/constructs/agentic-check.mdx index 9589c031..26c6c8f5 100644 --- a/constructs/agentic-check.mdx +++ b/constructs/agentic-check.mdx @@ -30,6 +30,7 @@ For additional setup information, see [CLI overview](/cli/overview). +{/* typecheck-skip */} ```typescript Basic Example import { AgenticCheck, Frequency } from 'checkly/constructs' @@ -41,6 +42,7 @@ new AgenticCheck('homepage-health', { }) ``` +{/* typecheck-skip */} ```typescript Skills import { AgenticCheck, Frequency } from 'checkly/constructs' @@ -167,6 +169,7 @@ Keep prompts focused on one flow. If you want to monitor navigation, login, and How often the Agentic Check should run. Use one of the supported `Frequency` constants or the equivalent number of minutes. +{/* typecheck-skip */} ```typescript import { AgenticCheck, Frequency } from 'checkly/constructs' diff --git a/detect/synthetic-monitoring/agentic-checks/configuration.mdx b/detect/synthetic-monitoring/agentic-checks/configuration.mdx index 83c6e298..0fdff69a 100644 --- a/detect/synthetic-monitoring/agentic-checks/configuration.mdx +++ b/detect/synthetic-monitoring/agentic-checks/configuration.mdx @@ -48,6 +48,7 @@ If an existing prompt covers unrelated paths, split them into separate replaceme Agentic Checks do **not** automatically expose all account variables or secrets to the agent. To expose one to an Agentic Check, reference it directly in the prompt with double curly brackets, such as `{{TEST_USER_EMAIL}}`. +{/* typecheck-skip */} ```typescript checkout.agentic.check.ts import { AgenticCheck, Frequency } from 'checkly/constructs' @@ -69,6 +70,7 @@ Some applications block automated monitoring unless requests include required he Agentic Checks include a default browser automation skill. You can add extra skills when the agent needs domain-specific capabilities. +{/* typecheck-skip */} ```typescript agentic-runtime.check.ts import { AgenticCheck } from 'checkly/constructs' @@ -104,6 +106,7 @@ The CLI construct supports these frequencies: Use `activated: false` to keep an existing Agentic Check deactivated while preserving its configuration and history: +{/* typecheck-skip */} ```typescript draft.agentic.check.ts import { AgenticCheck } from 'checkly/constructs' From 97a1f7b61f7d1d9d4fbcbae550cfcba73b6deb43 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 13:10:41 +0100 Subject: [PATCH 08/29] Typecheck fragments marked with typecheck-wrap {/* typecheck-wrap: ApiCheck */} before a fence auto-imports the checkly exports and wraps property fragments in the named construct. --- .github/scripts/typecheck-snippets.mjs | 37 +++++++++---- .github/scripts/typecheck-snippets.test.mjs | 57 +++++++++++++++++++++ 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index 6f9f5649..36888c99 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -1,9 +1,10 @@ // Typechecks MDX code snippets that import from `checkly` against the // installed Checkly CLI constructs, so docs examples don't drift from the CLI. // -// Only complete snippets (ones with a `checkly` import) are checked. Snippets -// with a `/* More options... */` comment may omit required props. Opt a block -// out by putting `{/* typecheck-skip */}` on the line before its fence. +// Complete snippets (ones with a `checkly` import) are checked. Fragments are +// checked when `{/* typecheck-wrap: ApiCheck */}` is on the line before their +// fence. Snippets with a `/* More options... */` comment may omit required +// props. Opt a block out with `{/* typecheck-skip */}` on the line before it. // // Usage: node .github/scripts/typecheck-snippets.mjs [root] import { readdirSync, readFileSync, existsSync } from 'node:fs'; @@ -13,6 +14,7 @@ import ts from 'typescript'; const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..'); const SKIP_MARKER = '{/* typecheck-skip */}'; +const WRAP_MARKER = /^\{\/\* typecheck-wrap: (\w+) \*\/\}$/; const LANGS = { ts: 'ts', typescript: 'ts', js: 'js', javascript: 'js' }; const CHECKLY_IMPORT = /from\s+['"]checkly(\/[\w-]+)?['"]/; @@ -27,13 +29,14 @@ export function extractSnippets(mdx, file) { if (!match) return; let prev = i - 1; while (prev >= 0 && lines[prev].trim() === '') prev--; - open = { indent: match[1].length, ext: LANGS[match[2]], start: i + 1, body: [], skip: prev >= 0 && lines[prev].trim() === SKIP_MARKER }; + const marker = prev >= 0 ? lines[prev].trim() : ''; + open = { indent: match[1].length, ext: LANGS[match[2]], start: i + 1, body: [], skip: marker === SKIP_MARKER, wrap: marker.match(WRAP_MARKER)?.[1] }; return; } if (/^\s*```\s*$/.test(text)) { const code = open.body.join('\n'); - if (open.ext && !open.skip && CHECKLY_IMPORT.test(code)) { - snippets.push({ file, line: open.start + 1, ext: open.ext, code }); + if (open.ext && !open.skip && (open.wrap || CHECKLY_IMPORT.test(code))) { + snippets.push({ file, line: open.start + 1, ext: open.ext, code, ...(open.wrap && { wrap: open.wrap }) }); } open = null; return; @@ -66,8 +69,23 @@ const MISSING_PROPS = new Set([2739, 2740, 2741]); const isOnlyMissingProps = d => d.code === 2345 && typeof d.messageText === 'object' && d.messageText.next?.length > 0 && d.messageText.next.every(n => MISSING_PROPS.has(n.code)); +// Fragments marked with `{/* typecheck-wrap: ApiCheck */}` get every runtime +// export of `checkly/constructs` and `checkly/util` imported. Property +// fragments are wrapped in the named construct as a partial snippet; +// fragments that already call a constructor only get the imports. +const AUTO_IMPORTS = [ + `import { ${Object.keys(await import('checkly/constructs')).join(', ')} } from 'checkly/constructs'`, + `import { ${Object.keys(await import('checkly/util')).join(', ')} } from 'checkly/util'`, +].join('; '); + +function source(snippet) { + if (!snippet.wrap) return { code: snippet.code, offset: 0 }; + if (/^\s*new\s/.test(snippet.code)) return { code: `${AUTO_IMPORTS}\n${snippet.code}`, offset: 1 }; + return { code: `${AUTO_IMPORTS}\nnew ${snippet.wrap}('snippet', {\n/* More options... */\n${snippet.code}\n})`, offset: 3 }; +} + export function typecheckSnippets(snippets) { - const virtual = new Map(snippets.map((s, i) => [join(repoRoot, '.snippets', `${i}.${s.ext}`).split(sep).join('/'), s])); + const virtual = new Map(snippets.map((s, i) => [join(repoRoot, '.snippets', `${i}.${s.ext}`).split(sep).join('/'), { ...s, ...source(s) }])); const host = ts.createCompilerHost(compilerOptions); const { getSourceFile, fileExists, readFile } = host; host.fileExists = f => virtual.has(f) || fileExists(f); @@ -88,10 +106,11 @@ export function typecheckSnippets(snippets) { .filter(d => !isUnresolvedRelativeImport(d) && !(partial && isOnlyMissingProps(d))); for (const d of diagnostics) { const { line, character } = source.getLineAndCharacterOfPosition(d.start ?? 0); + // Errors in generated wrapper lines point at the fragment's first line. errors.push({ file: snippet.file, - line: snippet.line + line, - column: character + 1, + line: snippet.line + Math.max(0, line - snippet.offset), + column: line < snippet.offset ? 1 : character + 1, message: `TS${d.code}: ${ts.flattenDiagnosticMessageText(d.messageText, '\n')}`, }); } diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index ea8fd3b0..147099cd 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -70,6 +70,20 @@ test('skips a block preceded by a typecheck-skip comment', () => { assert.equal(snippets[0].line, 7); }); +test('extracts fragments marked with typecheck-wrap even without a checkly import', () => { + const mdx = [ + '{/* typecheck-wrap: ApiCheck */}', + `${fence}ts REST API`, + `request: { method: 'GET', url: 'https://x.dev' },`, + fence, + ].join('\n'); + + const [fragment] = extractSnippets(mdx, 'page.mdx'); + + assert.equal(fragment.wrap, 'ApiCheck'); + assert.equal(fragment.line, 3); +}); + function snippet(code, line = 10) { return { file: 'page.mdx', line, ext: 'ts', code }; } @@ -144,6 +158,49 @@ test('reports missing required props in complete snippets', () => { assert.match(errors[0].message, /'code' is missing/); }); +function fragment(code, wrap = 'ApiCheck', line = 10) { + return { file: 'page.mdx', line, ext: 'ts', code, wrap }; +} + +test('typechecks a property fragment inside the wrap construct with auto-imports', () => { + const errors = typecheckSnippets([fragment([ + `request: {`, + ` method: 'GET',`, + ` url: 'https://x.dev',`, + ` assertions: [AssertionBuilder.statusCode().equals(200)],`, + `},`, + `frequency: Frequency.EVERY_5M,`, + ].join('\n'))]); + + assert.deepEqual(errors, []); +}); + +test('reports wrong props in a wrapped fragment at the MDX line', () => { + const errors = typecheckSnippets([fragment([ + `request: {`, + ` method: 'GTE',`, + ` url: 'https://x.dev',`, + `},`, + ].join('\n'))]); + + assert.equal(errors.length, 1); + assert.equal(errors[0].line, 11); + assert.match(errors[0].message, /GTE/); +}); + +test('only adds imports to a marked fragment that already calls the constructor', () => { + const errors = typecheckSnippets([fragment([ + `new ApiCheck('a', {`, + ` name: 'A',`, + ` maxResponseTime: 'slow',`, + ` request: { method: 'GET', url: 'https://x.dev' },`, + `})`, + ].join('\n'))]); + + assert.equal(errors.length, 1); + assert.equal(errors[0].line, 12); +}); + test('reports syntax errors without hiding type errors in other snippets', () => { const errors = typecheckSnippets([ snippet(`import { ApiCheck } from 'checkly/constructs'\nnew ApiCheck('a', {\n ...\n})`, 10), From 40401fd51c2d6244809f19ddf6a5daee7028b44d Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 13:12:09 +0100 Subject: [PATCH 09/29] Typecheck ApiCheck fragments on the api-check reference page Mark fragments with typecheck-wrap, auto-import path for entrypoints, and add the missing request method to the inline setup script example. --- .github/scripts/typecheck-snippets.mjs | 8 +++++--- .github/scripts/typecheck-snippets.test.mjs | 6 ++++++ constructs/api-check.mdx | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index 36888c99..33e7a350 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -70,12 +70,14 @@ const isOnlyMissingProps = d => d.code === 2345 && typeof d.messageText === 'obj && d.messageText.next?.length > 0 && d.messageText.next.every(n => MISSING_PROPS.has(n.code)); // Fragments marked with `{/* typecheck-wrap: ApiCheck */}` get every runtime -// export of `checkly/constructs` and `checkly/util` imported. Property -// fragments are wrapped in the named construct as a partial snippet; -// fragments that already call a constructor only get the imports. +// export of `checkly/constructs` and `checkly/util` imported, plus `path` for +// `path.join(__dirname, ...)` entrypoints. Property fragments are wrapped in +// the named construct as a partial snippet; fragments that already call a +// constructor only get the imports. const AUTO_IMPORTS = [ `import { ${Object.keys(await import('checkly/constructs')).join(', ')} } from 'checkly/constructs'`, `import { ${Object.keys(await import('checkly/util')).join(', ')} } from 'checkly/util'`, + `import * as path from 'node:path'`, ].join('; '); function source(snippet) { diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index 147099cd..71736489 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -188,6 +188,12 @@ test('reports wrong props in a wrapped fragment at the MDX line', () => { assert.match(errors[0].message, /GTE/); }); +test('auto-imports node:path for fragments that reference entrypoint files', () => { + const errors = typecheckSnippets([fragment(`setupScript: { entrypoint: path.join(__dirname, 'setup.ts') },`)]); + + assert.deepEqual(errors, []); +}); + test('only adds imports to a marked fragment that already calls the constructor', () => { const errors = typecheckSnippets([fragment([ `new ApiCheck('a', {`, diff --git a/constructs/api-check.mdx b/constructs/api-check.mdx index 18ac4fa2..62be0a29 100644 --- a/constructs/api-check.mdx +++ b/constructs/api-check.mdx @@ -123,6 +123,7 @@ The HTTP request configuration that defines the API endpoint to monitor. This is **Usage:** +{/* typecheck-wrap: ApiCheck */} ```ts request: { method: 'GET', @@ -149,6 +150,7 @@ request: { +{/* typecheck-wrap: ApiCheck */} ```ts REST API request: { method: "GET", @@ -165,6 +167,7 @@ request: { }, ``` +{/* typecheck-wrap: ApiCheck */} ```ts GraphQL API request: { method: "POST", @@ -190,6 +193,7 @@ request: { }, ``` +{/* typecheck-wrap: ApiCheck */} ```ts Form POST request: { method: "POST", @@ -205,6 +209,7 @@ request: { }, ``` +{/* typecheck-wrap: ApiCheck */} ```ts API with Authentication request: { method: "GET", @@ -230,6 +235,7 @@ Response time threshold in milliseconds for marking the check as degraded. This **Usage:** +{/* typecheck-wrap: ApiCheck */} ```ts highlight={3} new ApiCheck("performance-check", { name: "Performance Monitoring", @@ -250,6 +256,7 @@ Maximum response time in milliseconds before marking the check as failed. This s **Usage:** +{/* typecheck-wrap: ApiCheck */} ```ts highlight={3} new ApiCheck("timeout-check", { name: "API Timeout Check", @@ -269,6 +276,7 @@ Whether a failure should count as a pass. When set to `true`, HTTP status codes **Usage:** +{/* typecheck-wrap: ApiCheck */} ```ts highlight={3} new ApiCheck("negative-test", { name: "Test Error Handling", @@ -284,6 +292,7 @@ new ApiCheck("negative-test", { +{/* typecheck-wrap: ApiCheck */} ```ts Error Testing new ApiCheck("error-handling-test", { name: "Error Handling Test", @@ -297,6 +306,7 @@ new ApiCheck("error-handling-test", { }) ``` +{/* typecheck-wrap: ApiCheck */} ```ts Rate Limit Testing new ApiCheck("rate-limit-test", { name: "Rate Limit Behavior", @@ -324,6 +334,7 @@ Script to run before the API Check execution. Useful for setting up test data or +{/* typecheck-wrap: ApiCheck */} ```ts File Reference highlight={3-5} new ApiCheck("api-with-setup", { name: "API with Setup Script", @@ -337,6 +348,7 @@ new ApiCheck("api-with-setup", { }) ``` +{/* typecheck-wrap: ApiCheck */} ```ts Inline Script highlight={3-8} new ApiCheck('inline-setup', { name: 'API with Inline Setup', @@ -347,6 +359,7 @@ new ApiCheck('inline-setup', { ` }, request: { + method: 'GET', url: 'https://api.example.com/users' } }) @@ -377,6 +390,7 @@ Script to run after the API Check execution. Useful for cleaning up test data or +{/* typecheck-wrap: ApiCheck */} ```ts File Reference highlight={3-5} new ApiCheck("api-with-teardown", { name: "API with Teardown Script", @@ -390,6 +404,7 @@ new ApiCheck("api-with-teardown", { }) ``` +{/* typecheck-wrap: ApiCheck */} ```ts Inline Script highlight={3-9} new ApiCheck("inline-teardown", { name: "API with Inline Teardown", @@ -472,6 +487,7 @@ AssertionBuilder.headers('strict-transport-security', 'max-age=(\\d+)').greaterT +{/* typecheck-wrap: ApiCheck */} ```ts REST API Check new ApiCheck("users-api-check", { name: "Users API Check", @@ -493,6 +509,7 @@ new ApiCheck("users-api-check", { }) ``` +{/* typecheck-wrap: ApiCheck */} ```ts GraphQL API Check new ApiCheck("graphql-api-check", { name: "GraphQL API Check", @@ -521,6 +538,7 @@ new ApiCheck("graphql-api-check", { }) ``` +{/* typecheck-wrap: ApiCheck */} ```ts Form Submission Check new ApiCheck("form-api-check", { name: "Form Submission Check", @@ -539,6 +557,7 @@ new ApiCheck("form-api-check", { }) ``` +{/* typecheck-wrap: ApiCheck */} ```ts Authenticated API Check new ApiCheck("protected-api-check", { name: "Protected API Check", From f7b5962bfc2f5870c1c637de44ea6e4385f05328 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 13:18:20 +0100 Subject: [PATCH 10/29] Support statement fragments and defineConfig in typecheck-wrap --- .github/scripts/typecheck-snippets.mjs | 24 +++++++++------- .github/scripts/typecheck-snippets.test.mjs | 31 +++++++++++++++++++++ 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index 33e7a350..8a421255 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -2,8 +2,8 @@ // installed Checkly CLI constructs, so docs examples don't drift from the CLI. // // Complete snippets (ones with a `checkly` import) are checked. Fragments are -// checked when `{/* typecheck-wrap: ApiCheck */}` is on the line before their -// fence. Snippets with a `/* More options... */` comment may omit required +// checked when `{/* typecheck-wrap: ApiCheck */}` (or `{/* typecheck-wrap */}` +// for statements) is on the line before their fence. Snippets with a `/* More options... */` comment may omit required // props. Opt a block out with `{/* typecheck-skip */}` on the line before it. // // Usage: node .github/scripts/typecheck-snippets.mjs [root] @@ -14,7 +14,7 @@ import ts from 'typescript'; const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..'); const SKIP_MARKER = '{/* typecheck-skip */}'; -const WRAP_MARKER = /^\{\/\* typecheck-wrap: (\w+) \*\/\}$/; +const WRAP_MARKER = /^\{\/\* typecheck-wrap(?:: (\w+))? \*\/\}$/; const LANGS = { ts: 'ts', typescript: 'ts', js: 'js', javascript: 'js' }; const CHECKLY_IMPORT = /from\s+['"]checkly(\/[\w-]+)?['"]/; @@ -30,7 +30,8 @@ export function extractSnippets(mdx, file) { let prev = i - 1; while (prev >= 0 && lines[prev].trim() === '') prev--; const marker = prev >= 0 ? lines[prev].trim() : ''; - open = { indent: match[1].length, ext: LANGS[match[2]], start: i + 1, body: [], skip: marker === SKIP_MARKER, wrap: marker.match(WRAP_MARKER)?.[1] }; + const wrap = marker.match(WRAP_MARKER); + open = { indent: match[1].length, ext: LANGS[match[2]], start: i + 1, body: [], skip: marker === SKIP_MARKER, wrap: wrap ? wrap[1] ?? true : undefined }; return; } if (/^\s*```\s*$/.test(text)) { @@ -69,20 +70,23 @@ const MISSING_PROPS = new Set([2739, 2740, 2741]); const isOnlyMissingProps = d => d.code === 2345 && typeof d.messageText === 'object' && d.messageText.next?.length > 0 && d.messageText.next.every(n => MISSING_PROPS.has(n.code)); -// Fragments marked with `{/* typecheck-wrap: ApiCheck */}` get every runtime -// export of `checkly/constructs` and `checkly/util` imported, plus `path` for -// `path.join(__dirname, ...)` entrypoints. Property fragments are wrapped in -// the named construct as a partial snippet; fragments that already call a -// constructor only get the imports. +// Marked fragments get every runtime export of `checkly/constructs` and +// `checkly/util` imported, plus `defineConfig` and `path` for +// `path.join(__dirname, ...)` entrypoints. Property fragments (first code line +// is `key: ...`) are wrapped in the named construct as a partial snippet; +// statements like `new ApiCheck(...)` or `const x = ...` only get the imports. const AUTO_IMPORTS = [ `import { ${Object.keys(await import('checkly/constructs')).join(', ')} } from 'checkly/constructs'`, `import { ${Object.keys(await import('checkly/util')).join(', ')} } from 'checkly/util'`, + `import { defineConfig } from 'checkly'`, `import * as path from 'node:path'`, ].join('; '); +const isPropertyFragment = code => /^\w+\??:\s/.test(code.split('\n').map(l => l.trim()).find(l => l && !l.startsWith('//')) ?? ''); + function source(snippet) { if (!snippet.wrap) return { code: snippet.code, offset: 0 }; - if (/^\s*new\s/.test(snippet.code)) return { code: `${AUTO_IMPORTS}\n${snippet.code}`, offset: 1 }; + if (typeof snippet.wrap !== 'string' || !isPropertyFragment(snippet.code)) return { code: `${AUTO_IMPORTS}\n${snippet.code}`, offset: 1 }; return { code: `${AUTO_IMPORTS}\nnew ${snippet.wrap}('snippet', {\n/* More options... */\n${snippet.code}\n})`, offset: 3 }; } diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index 71736489..f4226cd7 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -194,6 +194,37 @@ test('auto-imports node:path for fragments that reference entrypoint files', () assert.deepEqual(errors, []); }); +test('extracts fragments marked with typecheck-wrap without a construct name', () => { + const mdx = ['{/* typecheck-wrap */}', `${fence}ts`, `UrlAssertionBuilder.statusCode().equals(200)`, fence].join('\n'); + + const [marked] = extractSnippets(mdx, 'page.mdx'); + + assert.equal(marked.wrap, true); +}); + +test('only adds imports to statement fragments', () => { + const errors = typecheckSnippets([ + fragment(`const alert = AlertEscalationBuilder.runBasedEscalation(2)`, true), + fragment(`UrlAssertionBuilder.statusCode().equals(200)`, true), + fragment(`UrlAssertionBuilder.statusCode().isFast()`, true, 30), + ]); + + assert.deepEqual(errors.map(e => e.line), [30]); +}); + +test('auto-imports defineConfig from checkly', () => { + const errors = typecheckSnippets([fragment(`export default defineConfig({\n projectName: 'P',\n logicalId: 'p',\n})`, true)]); + + assert.deepEqual(errors, []); +}); + +test('wraps property fragments that start with a comment', () => { + const errors = typecheckSnippets([fragment(`// Fail fast\nmaxResponseTime: 'slow',`)]); + + assert.equal(errors.length, 1); + assert.equal(errors[0].line, 11); +}); + test('only adds imports to a marked fragment that already calls the constructor', () => { const errors = typecheckSnippets([fragment([ `new ApiCheck('a', {`, From ebef3af5e1988c5cd4ffa32aaa56d6acfd8c751d Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 13:19:49 +0100 Subject: [PATCH 11/29] Treat undeclared lowercase names in fragments as page context --- .github/scripts/typecheck-snippets.mjs | 8 +++++++- .github/scripts/typecheck-snippets.test.mjs | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index 8a421255..24f68082 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -82,6 +82,12 @@ const AUTO_IMPORTS = [ `import * as path from 'node:path'`, ].join('; '); +// Fragments reference values defined elsewhere on the page (`statusPage`, +// `group`). Checkly exports are auto-imported, so an unknown lowercase name is +// page context; an unknown PascalCase name is a missing or misspelled construct. +const isPageContextName = d => (d.code === 2304 || d.code === 18004) + && /'[a-z_$][\w$]*'/.test(ts.flattenDiagnosticMessageText(d.messageText, '\n')); + const isPropertyFragment = code => /^\w+\??:\s/.test(code.split('\n').map(l => l.trim()).find(l => l && !l.startsWith('//')) ?? ''); function source(snippet) { @@ -109,7 +115,7 @@ export function typecheckSnippets(snippets) { // Type errors on code that doesn't parse are noise; report the parse errors only. const partial = PARTIAL_MARKER.test(snippet.code); const diagnostics = syntactic.length > 0 ? syntactic : program.getSemanticDiagnostics(source) - .filter(d => !isUnresolvedRelativeImport(d) && !(partial && isOnlyMissingProps(d))); + .filter(d => !isUnresolvedRelativeImport(d) && !(partial && isOnlyMissingProps(d)) && !(snippet.wrap && isPageContextName(d))); for (const d of diagnostics) { const { line, character } = source.getLineAndCharacterOfPosition(d.start ?? 0); // Errors in generated wrapper lines point at the fragment's first line. diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index f4226cd7..a0c7aa76 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -212,6 +212,16 @@ test('only adds imports to statement fragments', () => { assert.deepEqual(errors.map(e => e.line), [30]); }); +test('ignores undeclared lowercase names in fragments, which refer to page context', () => { + const errors = typecheckSnippets([ + fragment(`new ApiCheck('api', {\n group,\n name: 'API',\n alertChannels: [slackChannel],\n request: { method: 'GET', url: 'https://x.dev' },\n})`), + fragment(`new NotAConstruct('a', {})`, true, 30), + snippet(`import { ApiCheck } from 'checkly/constructs'\nnew ApiCheck('a', { name: 'A', group, request: { method: 'GET', url: 'https://x.dev' } })`, 50), + ]); + + assert.deepEqual(errors.map(e => e.line), [30, 51]); +}); + test('auto-imports defineConfig from checkly', () => { const errors = typecheckSnippets([fragment(`export default defineConfig({\n projectName: 'P',\n logicalId: 'p',\n})`, true)]); From fa78257b89f72d068411285af6520fa52983e68c Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 13:22:07 +0100 Subject: [PATCH 12/29] Auto-import checkly type exports into TS fragments --- .github/scripts/typecheck-snippets.mjs | 28 ++++++++++++++++----- .github/scripts/typecheck-snippets.test.mjs | 15 +++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index 24f68082..6d6c68b6 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -70,17 +70,32 @@ const MISSING_PROPS = new Set([2739, 2740, 2741]); const isOnlyMissingProps = d => d.code === 2345 && typeof d.messageText === 'object' && d.messageText.next?.length > 0 && d.messageText.next.every(n => MISSING_PROPS.has(n.code)); -// Marked fragments get every runtime export of `checkly/constructs` and +// Exports of a module read from its type declarations, split into values and +// types, because JavaScript files can't import types. +function moduleExports(specifiers) { + const files = specifiers.map(s => ts.resolveModuleName(s, join(repoRoot, 'index.ts'), compilerOptions, ts.sys).resolvedModule.resolvedFileName); + const program = ts.createProgram(files, compilerOptions); + const checker = program.getTypeChecker(); + return files.map(f => { + const symbols = checker.getExportsOfModule(checker.getSymbolAtLocation(program.getSourceFile(f))); + const isValue = s => ((s.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(s) : s).flags & ts.SymbolFlags.Value) !== 0; + return { all: symbols.map(s => s.name), values: symbols.filter(isValue).map(s => s.name) }; + }); +} + +// Marked fragments get every export of `checkly/constructs` and // `checkly/util` imported, plus `defineConfig` and `path` for // `path.join(__dirname, ...)` entrypoints. Property fragments (first code line // is `key: ...`) are wrapped in the named construct as a partial snippet; // statements like `new ApiCheck(...)` or `const x = ...` only get the imports. -const AUTO_IMPORTS = [ - `import { ${Object.keys(await import('checkly/constructs')).join(', ')} } from 'checkly/constructs'`, - `import { ${Object.keys(await import('checkly/util')).join(', ')} } from 'checkly/util'`, +const [constructExports, utilExports] = moduleExports(['checkly/constructs', 'checkly/util']); +const autoImports = kind => [ + `import { ${constructExports[kind].join(', ')} } from 'checkly/constructs'`, + `import { ${utilExports[kind].join(', ')} } from 'checkly/util'`, `import { defineConfig } from 'checkly'`, `import * as path from 'node:path'`, ].join('; '); +const AUTO_IMPORTS = { ts: autoImports('all'), js: autoImports('values') }; // Fragments reference values defined elsewhere on the page (`statusPage`, // `group`). Checkly exports are auto-imported, so an unknown lowercase name is @@ -92,8 +107,9 @@ const isPropertyFragment = code => /^\w+\??:\s/.test(code.split('\n').map(l => l function source(snippet) { if (!snippet.wrap) return { code: snippet.code, offset: 0 }; - if (typeof snippet.wrap !== 'string' || !isPropertyFragment(snippet.code)) return { code: `${AUTO_IMPORTS}\n${snippet.code}`, offset: 1 }; - return { code: `${AUTO_IMPORTS}\nnew ${snippet.wrap}('snippet', {\n/* More options... */\n${snippet.code}\n})`, offset: 3 }; + const imports = AUTO_IMPORTS[snippet.ext]; + if (typeof snippet.wrap !== 'string' || !isPropertyFragment(snippet.code)) return { code: `${imports}\n${snippet.code}`, offset: 1 }; + return { code: `${imports}\nnew ${snippet.wrap}('snippet', {\n/* More options... */\n${snippet.code}\n})`, offset: 3 }; } export function typecheckSnippets(snippets) { diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index a0c7aa76..dbc7d8c5 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -222,6 +222,21 @@ test('ignores undeclared lowercase names in fragments, which refer to page conte assert.deepEqual(errors.map(e => e.line), [30, 51]); }); +test('auto-imports type-only exports like IncidentTrigger', () => { + const errors = typecheckSnippets([ + fragment(`const trigger: IncidentTrigger = {\n name: 'Search down',\n description: 'Search is failing',\n severity: 'MAJOR',\n notifySubscribers: true,\n service: searchService,\n}`, true), + fragment(`const trigger: NotAType = {}`, true, 30), + ]); + + assert.deepEqual(errors.map(e => e.line), [30]); +}); + +test('auto-imports only value exports into JavaScript fragments', () => { + const errors = typecheckSnippets([{ ...fragment(`UrlAssertionBuilder.statusCode().equals(200)`, true), ext: 'js' }]); + + assert.deepEqual(errors, []); +}); + test('auto-imports defineConfig from checkly', () => { const errors = typecheckSnippets([fragment(`export default defineConfig({\n projectName: 'P',\n logicalId: 'p',\n})`, true)]); From a5a9f65d473f207d5220165b1799a11207f7d48c Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 13:22:52 +0100 Subject: [PATCH 13/29] Allow missing props on typed variables in partial snippets --- .github/scripts/typecheck-snippets.mjs | 4 ++-- .github/scripts/typecheck-snippets.test.mjs | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index 6d6c68b6..338abf94 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -67,8 +67,8 @@ const isUnresolvedRelativeImport = d => d.code === 2307 && /module '\.\.?\//.tes // a missing required prop is intended; wrong or unknown props still fail. const PARTIAL_MARKER = /\/\*\s*More options/i; const MISSING_PROPS = new Set([2739, 2740, 2741]); -const isOnlyMissingProps = d => d.code === 2345 && typeof d.messageText === 'object' - && d.messageText.next?.length > 0 && d.messageText.next.every(n => MISSING_PROPS.has(n.code)); +const isOnlyMissingProps = d => MISSING_PROPS.has(d.code) || (d.code === 2345 && typeof d.messageText === 'object' + && d.messageText.next?.length > 0 && d.messageText.next.every(n => MISSING_PROPS.has(n.code))); // Exports of a module read from its type declarations, split into values and // types, because JavaScript files can't import types. diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index dbc7d8c5..24c83fac 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -142,6 +142,14 @@ test('allows missing required props in snippets marked with a "More options" com assert.deepEqual(errors, []); }); +test('allows missing required props on typed variables marked with a "More options" comment', () => { + const errors = typecheckSnippets([ + fragment(`const trigger: IncidentTrigger = {\n service: searchService,\n /* More options... */\n}`, true), + ]); + + assert.deepEqual(errors, []); +}); + test('still reports wrong props in snippets marked with a "More options" comment', () => { const errors = typecheckSnippets([ snippet(`import { BrowserCheck } from 'checkly/constructs'\nnew BrowserCheck('a', {\n frequency: 'often',\n /* More options... */\n})`), From 1b2d4e21dabe8b5519dd0a6cd3c17350bb044542 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 13:23:55 +0100 Subject: [PATCH 14/29] Typecheck construct fragments across the docs Mark fragments with typecheck-wrap so they're checked against checkly@10. Add /* More options... */ to usage examples that omit required props, and projectName/logicalId to abbreviated checkly.config.ts examples. --- concepts/environments.mdx | 1 + constructs/alert-escalation-policy.mdx | 7 +++ constructs/browser-check.mdx | 14 ++++++ constructs/check-group-v2.mdx | 10 ++++ constructs/check-group.mdx | 9 ++++ constructs/dashboard.mdx | 12 +++++ constructs/dns-monitor.mdx | 13 ++++- constructs/grpc-monitor.mdx | 7 +++ constructs/heartbeat-monitor.mdx | 22 ++++++++- constructs/icmp-monitor.mdx | 13 ++++- constructs/incident-trigger.mdx | 1 + constructs/incidentio-alert-channel.mdx | 1 + constructs/including-checks.mdx | 17 +++++-- constructs/maintenance-window.mdx | 18 +++++++ constructs/msteams-alert-channel.mdx | 1 + constructs/multistep-check.mdx | 8 +++- constructs/overview.mdx | 3 +- constructs/phone-call-alert-channel.mdx | 1 + constructs/playwright-check.mdx | 22 +++++++++ constructs/private-location.mdx | 15 ++++++ constructs/project.mdx | 23 +++++++++ constructs/retry-strategy.mdx | 16 +++++++ constructs/slack-alert-channel.mdx | 1 + constructs/slack-app-alert-channel.mdx | 1 + constructs/sms-alert-channel.mdx | 1 + constructs/ssl-monitor.mdx | 7 +++ constructs/status-page-service.mdx | 2 + constructs/status-page-v3-automation-rule.mdx | 2 + constructs/status-page-v3-component.mdx | 4 ++ constructs/status-page-v3.mdx | 3 ++ constructs/status-page.mdx | 10 ++++ constructs/tcp-monitor.mdx | 29 +++++++++++- constructs/telegram-alert-channel.mdx | 1 + constructs/traceroute-monitor.mdx | 7 +++ constructs/url-monitor.mdx | 47 +++++++++++++++---- constructs/webhook-alert-channel.mdx | 4 ++ .../playwright-checks/configuration.mdx | 5 +- .../playwright-checks/overview.mdx | 3 ++ .../playwright-checks/quickstart.mdx | 3 ++ .../playwright-checks/test-organization.mdx | 35 +++++++++++--- guides/communicate-availability.mdx | 1 + integrations/iac/pulumi/best-practices.mdx | 1 + snippets/alert-channel-options-text.mdx | 2 + 43 files changed, 374 insertions(+), 29 deletions(-) diff --git a/concepts/environments.mdx b/concepts/environments.mdx index 48c6b9cb..3115aa2c 100644 --- a/concepts/environments.mdx +++ b/concepts/environments.mdx @@ -196,6 +196,7 @@ The following example deploys one shared API check to development, staging, and When an environment needs additional or different checks, keep shared checks in one directory and select the environment-specific directory from your configuration: +{/* typecheck-wrap */} ```typescript checkly.config.ts const sharedChecks = "**/__checks__/shared/**/*.check.ts" const environmentChecks = `**/__checks__/${environment}/**/*.check.ts` diff --git a/constructs/alert-escalation-policy.mdx b/constructs/alert-escalation-policy.mdx index 002388cb..78cd8573 100644 --- a/constructs/alert-escalation-policy.mdx +++ b/constructs/alert-escalation-policy.mdx @@ -65,6 +65,7 @@ Creates an alert escalation policy that triggers after a specified number of con **Usage:** +{/* typecheck-wrap */} ```ts AlertEscalationBuilder.runBasedEscalation( failedRuns, @@ -85,6 +86,7 @@ AlertEscalationBuilder.runBasedEscalation( +{/* typecheck-wrap */} ```ts Immediate Alert // Alert immediately on first failure const immediateAlert = AlertEscalationBuilder.runBasedEscalation( @@ -102,6 +104,7 @@ new ApiCheck("critical-service-check", { }) ``` +{/* typecheck-wrap */} ```ts Conservative Alert // Wait for multiple failures before alerting const conservativeAlert = AlertEscalationBuilder.runBasedEscalation( @@ -133,6 +136,7 @@ Creates an alert escalation policy that triggers after a specified duration of c **Usage:** +{/* typecheck-wrap */} ```ts AlertEscalationBuilder.timeBasedEscalation( minutesFailing, @@ -153,6 +157,7 @@ AlertEscalationBuilder.timeBasedEscalation( +{/* typecheck-wrap */} ```ts Alert after 15 minutes // Wait for batch jobs or slow services const timeBasedAlert = AlertEscalationBuilder.timeBasedEscalation( @@ -252,6 +257,7 @@ parallelRunFailureThreshold: { +{/* typecheck-wrap */} ```ts Regional Redundancy // Only alert if majority of regions fail const regionalAlert = AlertEscalationBuilder.runBasedEscalation( @@ -272,6 +278,7 @@ new ApiCheck("global-service-check", { }) ``` +{/* typecheck-wrap */} ```ts CDN Monitoring // Alert if 10% of CDN edges are failing const cdnAlert = AlertEscalationBuilder.runBasedEscalation( diff --git a/constructs/browser-check.mdx b/constructs/browser-check.mdx index 738b4887..ea835811 100644 --- a/constructs/browser-check.mdx +++ b/constructs/browser-check.mdx @@ -145,6 +145,7 @@ You must provide either `entrypoint` or `content`, but not both. +{/* typecheck-wrap: BrowserCheck */} ```ts File Reference new BrowserCheck("login-flow-check", { name: "User Login Flow", @@ -200,6 +201,7 @@ Friendly name for your Browser Check that will be displayed in the Checkly dashb **Usage:** +{/* typecheck-wrap: BrowserCheck */} ```ts highlight={2} new BrowserCheck("my-check", { name: "User Login Flow Test", @@ -228,6 +230,7 @@ new BrowserCheck("my-check", { +{/* typecheck-wrap: BrowserCheck */} ```ts High Frequency // For critical user journeys new BrowserCheck("critical-login", { @@ -238,6 +241,7 @@ new BrowserCheck("critical-login", { }) ``` +{/* typecheck-wrap: BrowserCheck */} ```ts Standard Frequency // For regular monitoring new BrowserCheck("standard-check", { @@ -261,6 +265,7 @@ Use `runtimeId` for Browser Checks and Multistep Checks. For Playwright Check Su **Usage:** +{/* typecheck-wrap: BrowserCheck */} ```ts highlight={3} new BrowserCheck("my-check", { name: "My Browser Check", @@ -278,6 +283,7 @@ Array of public location codes where the Browser Check should run. Multiple loca **Usage:** +{/* typecheck-wrap: BrowserCheck */} ```ts highlight={3} new BrowserCheck("my-check", { name: "My Browser Check", @@ -290,6 +296,7 @@ new BrowserCheck("my-check", { +{/* typecheck-wrap: BrowserCheck */} ```ts Global Coverage // Comprehensive global monitoring new BrowserCheck("global-check", { @@ -305,6 +312,7 @@ new BrowserCheck("global-check", { }) ``` +{/* typecheck-wrap: BrowserCheck */} ```ts Regional Focus // Focus on specific regions new BrowserCheck("europe-check", { @@ -324,6 +332,7 @@ Whether the browser check is enabled and will run according to its schedule. **Usage:** +{/* typecheck-wrap: BrowserCheck */} ```ts highlight={3} new BrowserCheck("my-check", { name: "My Browser Check", @@ -340,6 +349,7 @@ Array of tags to organize and categorize your Browser Checks in the Checkly infr **Usage:** +{/* typecheck-wrap: BrowserCheck */} ```ts highlight={3} new BrowserCheck("my-check", { name: "My Browser Check", @@ -352,6 +362,7 @@ new BrowserCheck("my-check", { +{/* typecheck-wrap: BrowserCheck */} ```ts Functional Tags new BrowserCheck("login-test", { name: "User Authentication", @@ -361,6 +372,7 @@ new BrowserCheck("login-test", { }) ``` +{/* typecheck-wrap: BrowserCheck */} ```ts Priority Tags new BrowserCheck("checkout-flow", { name: "Checkout Process", @@ -370,6 +382,7 @@ new BrowserCheck("checkout-flow", { }) ``` +{/* typecheck-wrap: BrowserCheck */} ```ts Environment Tags new BrowserCheck("staging-test", { name: "Staging Environment Test", @@ -430,6 +443,7 @@ new BrowserCheck("user-flow", { }) ``` +{/* typecheck-wrap: BrowserCheck */} ```ts Feature Flags new BrowserCheck("feature-test", { name: "Feature Flag Test", diff --git a/constructs/check-group-v2.mdx b/constructs/check-group-v2.mdx index 330b29d5..e45b0a65 100644 --- a/constructs/check-group-v2.mdx +++ b/constructs/check-group-v2.mdx @@ -111,6 +111,7 @@ Friendly name for your check group that will be displayed in the Checkly dashboa **Usage:** +{/* typecheck-wrap: CheckGroupV2 */} ```ts highlight={2} const group = new CheckGroupV2("api-monitoring-group", { name: "API Monitoring Group", @@ -126,6 +127,7 @@ Whether checks in the group are running. When false, all checks in the group are **Usage:** +{/* typecheck-wrap: CheckGroupV2 */} ```ts highlight={3} const group = new CheckGroupV2("api-monitoring-group", { name: "API Monitoring Group", @@ -142,6 +144,7 @@ Whether to mute alerts for all checks in the group. Checks will still run but wo **Usage:** +{/* typecheck-wrap: CheckGroupV2 */} ```ts highlight={3} const group = new CheckGroupV2("api-monitoring-group", { name: "API Monitoring Group", @@ -176,6 +179,7 @@ Public locations for all checks in the group. If this or `privateLocations` is s **Usage:** +{/* typecheck-wrap: CheckGroupV2 */} ```ts highlight={3} const group = new CheckGroupV2("api-monitoring-group", { name: "API Monitoring Group", @@ -192,6 +196,7 @@ Setting to automatically create and apply Browser Checks to a group. **Usage:** +{/* typecheck-wrap: CheckGroupV2 */} ```ts highlight={3-5} const group = new CheckGroupV2("api-monitoring-group", { name: "API Monitoring Group", @@ -210,6 +215,7 @@ Setting to automatically create and apply MultiStep Checks to a group. **Usage:** +{/* typecheck-wrap: CheckGroupV2 */} ```ts highlight={3-5} const group = new CheckGroupV2("api-multistep-group", { name: "API Multistep Monitoring Group", @@ -247,6 +253,7 @@ To add checks to an existing group in your account, find the group ID in the Che +{/* typecheck-wrap */} ```ts Using Existing Group highlight={2,6} // Reference an existing group by ID const existingGroup = CheckGroupV2.fromId(123) @@ -280,6 +287,7 @@ See [Mixing Checks and Monitors in a Group](/platform/groups/#mixing-checks-and- + {/* typecheck-wrap: CheckGroupV2 */} ```ts const apiGroup = new CheckGroupV2("api-monitoring-group", { name: "API Monitoring", @@ -316,6 +324,7 @@ See [Mixing Checks and Monitors in a Group](/platform/groups/#mixing-checks-and- + {/* typecheck-wrap: CheckGroupV2 */} ```ts const servicesGroup = new CheckGroupV2("services-monitoring", { name: "Core Services Monitoring", @@ -364,6 +373,7 @@ See [Mixing Checks and Monitors in a Group](/platform/groups/#mixing-checks-and- + {/* typecheck-wrap: CheckGroupV2 */} ```ts const regionalGroup = new CheckGroupV2("us-east-monitoring", { name: "US East Region Monitoring", diff --git a/constructs/check-group.mdx b/constructs/check-group.mdx index 7ff424f2..e78f8cbe 100644 --- a/constructs/check-group.mdx +++ b/constructs/check-group.mdx @@ -112,6 +112,7 @@ Friendly name for your check group that will be displayed in the Checkly dashboa **Usage:** +{/* typecheck-wrap: CheckGroup */} ```ts highlight={2} const group = new CheckGroup("api-monitoring-group", { name: "API Monitoring Group", @@ -126,6 +127,7 @@ Whether checks in the group are running. When false, all checks in the group are **Usage:** +{/* typecheck-wrap: CheckGroup */} ```ts highlight={3} const group = new CheckGroup("api-monitoring-group", { name: "API Monitoring Group", @@ -142,6 +144,7 @@ Whether to mute alerts for all checks in the group. Checks will still run but wo **Usage:** +{/* typecheck-wrap: CheckGroup */} ```ts highlight={3} const group = new CheckGroup("api-monitoring-group", { name: "API Monitoring Group", @@ -177,6 +180,7 @@ Public locations for all checks in the group. Checks inherit these locations unl **Usage:** +{/* typecheck-wrap: CheckGroup */} ```ts highlight={3} const group = new CheckGroup("api-monitoring-group", { name: "API Monitoring Group", @@ -193,6 +197,7 @@ Setting to automatically create and apply Browser Checks to a group. **Usage:** +{/* typecheck-wrap: CheckGroup */} ```ts highlight={3-5} const group = new CheckGroup("api-monitoring-group", { name: "API Monitoring Group", @@ -211,6 +216,7 @@ Setting to automatically create and apply MultiStep Checks to a group. **Usage:** +{/* typecheck-wrap: CheckGroup */} ```ts highlight={3-5} const group = new CheckGroup("api-multistep-group", { name: "API Multistep Monitoring Group", @@ -227,6 +233,7 @@ const group = new CheckGroup("api-multistep-group", { + {/* typecheck-wrap: CheckGroup */} ```ts const apiGroup = new CheckGroup("api-monitoring-group", { name: "API Monitoring", @@ -262,6 +269,7 @@ const group = new CheckGroup("api-multistep-group", { + {/* typecheck-wrap: CheckGroup */} ```ts const servicesGroup = new CheckGroup("services-monitoring", { name: "Core Services Monitoring", @@ -309,6 +317,7 @@ const group = new CheckGroup("api-multistep-group", { + {/* typecheck-wrap: CheckGroup */} ```ts const regionalGroup = new CheckGroup("us-east-monitoring", { name: "US East Region Monitoring", diff --git a/constructs/dashboard.mdx b/constructs/dashboard.mdx index 2642f1bb..9eeab13a 100644 --- a/constructs/dashboard.mdx +++ b/constructs/dashboard.mdx @@ -93,6 +93,7 @@ Text displayed at the top of your dashboard as the main title. **Usage:** +{/* typecheck-wrap: Dashboard */} ```ts highlight={2} new Dashboard('my-dashboard', { header: 'Production Services Status' @@ -108,6 +109,7 @@ Text displayed below the header providing additional context about the dashboard **Usage:** +{/* typecheck-wrap: Dashboard */} ```ts highlight={3} new Dashboard('my-dashboard', { header: 'Production Services', @@ -123,6 +125,7 @@ Tags that filter which checks appear on the dashboard. Empty array shows all che **Usage:** +{/* typecheck-wrap: Dashboard */} ```ts highlight={2} new Dashboard('my-dashboard', { tags: ['production', 'api'] @@ -131,6 +134,7 @@ new Dashboard('my-dashboard', { **Examples:** +{/* typecheck-wrap: Dashboard */} ```ts // Service-specific tags new Dashboard('api-dashboard', { @@ -161,6 +165,7 @@ Subdomain under "checklyhq.com" for your dashboard (e.g., "my-status" becomes "m **Usage:** +{/* typecheck-wrap: Dashboard */} ```ts highlight={2} new Dashboard('my-dashboard', { customUrl: 'service-status' @@ -181,6 +186,7 @@ Custom domain for your dashboard (e.g., "status.example.com"). Must be verified **Usage:** +{/* typecheck-wrap: Dashboard */} ```ts highlight={2} new Dashboard('my-dashboard', { customDomain: 'status.example.com' @@ -195,6 +201,7 @@ Custom CSS styling for your dashboard. Only available on Team and Enterprise pla **Usage:** +{/* typecheck-wrap: Dashboard */} ```ts highlight={3-5,10-20} // Using file reference new Dashboard("styled-dashboard", { @@ -237,6 +244,7 @@ You must provide either `entrypoint` or `content`, but not both. + {/* typecheck-wrap: Dashboard */} ```ts new Dashboard("production-monitoring", { header: "Production Services", @@ -254,6 +262,7 @@ You must provide either `entrypoint` or `content`, but not both. + {/* typecheck-wrap: Dashboard */} ```ts new Dashboard("api-dashboard", { header: "API Endpoints Status", @@ -270,6 +279,7 @@ You must provide either `entrypoint` or `content`, but not both. + {/* typecheck-wrap: Dashboard */} ```ts new Dashboard("us-east-dashboard", { header: "US East Region Status", @@ -286,6 +296,7 @@ You must provide either `entrypoint` or `content`, but not both. + {/* typecheck-wrap: Dashboard */} ```ts new Dashboard("platform-team-dashboard", { header: "Platform Team Services", @@ -303,6 +314,7 @@ You must provide either `entrypoint` or `content`, but not both. + {/* typecheck-wrap: Dashboard */} ```ts new Dashboard("branded-dashboard", { header: "ACME Corporation Status", diff --git a/constructs/dns-monitor.mdx b/constructs/dns-monitor.mdx index 375c7d56..9701a92b 100644 --- a/constructs/dns-monitor.mdx +++ b/constructs/dns-monitor.mdx @@ -107,6 +107,7 @@ DNS request configuration that defines the DNS query to perform and how to valid **Usage:** +{/* typecheck-wrap: DnsMonitor */} ```ts new DnsMonitor("dns-monitor", { name: "DNS A Record Monitor", @@ -138,6 +139,7 @@ Response time threshold in milliseconds for marking the DNS Monitor as degraded **Usage:** +{/* typecheck-wrap: DnsMonitor */} ```ts highlight={3} new DnsMonitor("dns-performance-tiers", { name: "DNS Performance Tiers", @@ -158,6 +160,7 @@ Maximum response time in milliseconds before the DNS Monitor is marked as failed **Usage:** +{/* typecheck-wrap: DnsMonitor */} ```ts highlight={3} new DnsMonitor("fast-dns", { name: "Fast DNS Resolution", @@ -214,6 +217,7 @@ Friendly name for your DNS Monitor that will be displayed in the Checkly dashboa **Usage:** +{/* typecheck-wrap: DnsMonitor */} ```ts highlight={2} new DnsMonitor("my-monitor", { name: "DNS Resolution Monitor", @@ -228,6 +232,7 @@ How often the DNS Monitor should run. Use the `Frequency` enum to set the check **Usage:** +{/* typecheck-wrap: DnsMonitor */} ```ts highlight={2} new DnsMonitor("my-monitor", { frequency: Frequency.EVERY_1M, @@ -243,9 +248,11 @@ Array of [public location codes](/concepts/locations/#public-locations) where th **Usage:** +{/* typecheck-wrap: DnsMonitor */} ```ts highlight={2} new DnsMonitor("global-dns-monitor", { - locations: ["us-east-1", "eu-central-1", "ap-southeast-1"] + locations: ["us-east-1", "eu-central-1", "ap-southeast-1"], + /* More options... */ }) ``` @@ -255,9 +262,11 @@ Whether the DNS Monitor is enabled and will run according to its schedule. **Usage:** +{/* typecheck-wrap: DnsMonitor */} ```ts highlight={2} new DnsMonitor("my-monitor", { - activated: false // Disabled monitor + activated: false, // Disabled monitor + /* More options... */ }) ``` diff --git a/constructs/grpc-monitor.mdx b/constructs/grpc-monitor.mdx index c1c18b28..b370fe8a 100644 --- a/constructs/grpc-monitor.mdx +++ b/constructs/grpc-monitor.mdx @@ -116,6 +116,7 @@ gRPC connection and call configuration. **Usage:** +{/* typecheck-wrap: GrpcMonitor */} ```ts new GrpcMonitor('grpc-monitor', { name: 'My gRPC Service', @@ -171,6 +172,7 @@ Response time in milliseconds at which the monitor is marked as degraded (warnin **Usage:** +{/* typecheck-wrap: GrpcMonitor */} ```ts highlight={3} new GrpcMonitor('grpc-thresholds', { name: 'gRPC Latency Thresholds', @@ -191,6 +193,7 @@ Response time in milliseconds at which the monitor is marked as failed. Maximum: **Usage:** +{/* typecheck-wrap: GrpcMonitor */} ```ts highlight={3} new GrpcMonitor('grpc-thresholds', { name: 'gRPC Latency Thresholds', @@ -267,6 +270,7 @@ Friendly name for your gRPC Monitor displayed in the Checkly dashboard and used **Usage:** +{/* typecheck-wrap: GrpcMonitor */} ```ts highlight={2} new GrpcMonitor('my-grpc-monitor', { name: 'User Service Health', @@ -281,6 +285,7 @@ How often the gRPC Monitor should run. Use the `Frequency` enum to set the check **Usage:** +{/* typecheck-wrap: GrpcMonitor */} ```ts highlight={3} new GrpcMonitor('my-grpc-monitor', { name: 'User Service Health', @@ -297,6 +302,7 @@ Array of [public location codes](/concepts/locations/#public-locations) where th **Usage:** +{/* typecheck-wrap: GrpcMonitor */} ```ts highlight={3} new GrpcMonitor('global-grpc-monitor', { name: 'Global gRPC Health', @@ -312,6 +318,7 @@ Whether the gRPC Monitor is enabled and will run according to its schedule. **Usage:** +{/* typecheck-wrap: GrpcMonitor */} ```ts highlight={3} new GrpcMonitor('my-grpc-monitor', { name: 'User Service Health', diff --git a/constructs/heartbeat-monitor.mdx b/constructs/heartbeat-monitor.mdx index 8d380d0a..3259957d 100644 --- a/constructs/heartbeat-monitor.mdx +++ b/constructs/heartbeat-monitor.mdx @@ -100,6 +100,7 @@ The expected period between pings from your external service. This defines how o **Usage:** +{/* typecheck-wrap: HeartbeatMonitor */} ```ts highlight={3} new HeartbeatMonitor('my-heartbeat', { name: "My heartbeat", @@ -114,6 +115,7 @@ new HeartbeatMonitor('my-heartbeat', { +{/* typecheck-wrap: HeartbeatMonitor */} ```ts // Daily backup job new HeartbeatMonitor("backup-job", { @@ -128,6 +130,7 @@ new HeartbeatMonitor("backup-job", { +{/* typecheck-wrap: HeartbeatMonitor */} ```ts // Hourly data sync new HeartbeatMonitor("data-sync", { @@ -142,6 +145,7 @@ new HeartbeatMonitor("data-sync", { +{/* typecheck-wrap: HeartbeatMonitor */} ```ts // Every 5 minutes new HeartbeatMonitor("frequent-task", { @@ -164,6 +168,7 @@ The time unit for the period. Defines whether the period is in seconds, minutes, **Usage:** +{/* typecheck-wrap: HeartbeatMonitor */} ```ts highlight={4} new HeartbeatMonitor("my-heartbeat", { name: "My heartbeat", @@ -181,12 +186,14 @@ The grace period to wait before alerting after the expected ping time has passed **Usage:** +{/* typecheck-wrap: HeartbeatMonitor */} ```ts highlight={4} new HeartbeatMonitor('my-heartbeat', { period: 1, periodUnit: 'hours', grace: 10, - graceUnit: 'minutes' // 10 minute grace period + graceUnit: 'minutes', // 10 minute grace period + /* More options... */ }) ``` @@ -195,6 +202,7 @@ new HeartbeatMonitor('my-heartbeat', { +{/* typecheck-wrap: HeartbeatMonitor */} ```ts // Strict timing requirements new HeartbeatMonitor("critical-task", { @@ -209,6 +217,7 @@ new HeartbeatMonitor("critical-task", { +{/* typecheck-wrap: HeartbeatMonitor */} ```ts // Standard tolerance new HeartbeatMonitor("standard-job", { @@ -223,6 +232,7 @@ new HeartbeatMonitor("standard-job", { +{/* typecheck-wrap: HeartbeatMonitor */} ```ts // Flexible timing for complex jobs new HeartbeatMonitor("complex-job", { @@ -245,12 +255,14 @@ The time unit for the grace period. Defines whether the grace period is in secon **Usage:** +{/* typecheck-wrap: HeartbeatMonitor */} ```ts highlight={5} new HeartbeatMonitor('my-heartbeat', { period: 6, periodUnit: 'hours', grace: 30, - graceUnit: 'minutes' // 30 minute grace period + graceUnit: 'minutes', // 30 minute grace period + /* More options... */ }) ``` @@ -264,6 +276,7 @@ Friendly name for your heartbeat monitor that will be displayed in the Checkly d **Usage:** +{/* typecheck-wrap: HeartbeatMonitor */} ```ts highlight={2} new HeartbeatMonitor('my-heartbeat', { name: 'Daily Backup Job Monitor', @@ -277,6 +290,7 @@ new HeartbeatMonitor('my-heartbeat', { + {/* typecheck-wrap: HeartbeatMonitor */} ```ts new HeartbeatMonitor("backup-job-heartbeat", { name: "Daily Database Backup", @@ -293,6 +307,7 @@ new HeartbeatMonitor('my-heartbeat', { + {/* typecheck-wrap: HeartbeatMonitor */} ```ts new HeartbeatMonitor("sync-job-heartbeat", { name: "Hourly Data Synchronization", @@ -316,6 +331,7 @@ new HeartbeatMonitor('my-heartbeat', { + {/* typecheck-wrap: HeartbeatMonitor */} ```ts new HeartbeatMonitor('deployment-heartbeat', { name: 'Production Deployment Pipeline', @@ -335,6 +351,7 @@ new HeartbeatMonitor('my-heartbeat', { + {/* typecheck-wrap: HeartbeatMonitor */} ```ts new HeartbeatMonitor('log-processing-heartbeat', { name: 'Log Processing Job', @@ -366,6 +383,7 @@ new HeartbeatMonitor('my-heartbeat', { + {/* typecheck-wrap: HeartbeatMonitor */} ```ts new HeartbeatMonitor('frequent-task-heartbeat', { name: 'Every Minute Task', diff --git a/constructs/icmp-monitor.mdx b/constructs/icmp-monitor.mdx index 1936b2de..76475606 100644 --- a/constructs/icmp-monitor.mdx +++ b/constructs/icmp-monitor.mdx @@ -95,6 +95,7 @@ ICMP request configuration, including ping settings and response validation. **Usage:** +{/* typecheck-wrap: IcmpMonitor */} ```ts new IcmpMonitor('icmp-monitor', { name: 'ICMP Latency Monitor', @@ -124,6 +125,7 @@ Packet loss percentage at which the monitor is marked as degraded (warning state **Usage:** +{/* typecheck-wrap: IcmpMonitor */} ```ts highlight={3} new IcmpMonitor("icmp-performance-tiers", { name: "ICMP Performance Tiers", @@ -141,6 +143,7 @@ Packet loss percentage at which the monitor is marked as failed **Usage:** +{/* typecheck-wrap: IcmpMonitor */} ```ts highlight={3} new IcmpMonitor("icmp-performance-tiers", { name: "ICMP Performance Tiers", @@ -188,6 +191,7 @@ Friendly name for your ICMP Monitor that will be displayed in the Checkly dashbo **Usage:** +{/* typecheck-wrap: IcmpMonitor */} ```ts highlight={2} new IcmpMonitor("my-monitor", { name: "ICMP Ping Monitor", @@ -202,6 +206,7 @@ How often the ICMP Monitor should run. Use the `Frequency` enum to set the check **Usage:** +{/* typecheck-wrap: IcmpMonitor */} ```ts highlight={3} new IcmpMonitor("my-monitor", { name: "ICMP Ping Monitor", @@ -218,10 +223,12 @@ Array of [public location codes](/concepts/locations/#public-locations) where th **Usage:** +{/* typecheck-wrap: IcmpMonitor */} ```ts highlight={3} new IcmpMonitor("global-icmp-monitor", { name: "ICMP Ping Monitor", - locations: ["us-east-1", "eu-central-1", "ap-southeast-1"] + locations: ["us-east-1", "eu-central-1", "ap-southeast-1"], + /* More options... */ }) ``` @@ -231,10 +238,12 @@ Whether the ICMP Monitor is enabled and will run according to its schedule. **Usage:** +{/* typecheck-wrap: IcmpMonitor */} ```ts highlight={3} new IcmpMonitor("my-monitor", { name: "ICMP Ping Monitor", - activated: false // Disabled monitor + activated: false, // Disabled monitor + /* More options... */ }) ``` diff --git a/constructs/incident-trigger.mdx b/constructs/incident-trigger.mdx index f84d9df6..c1dccf16 100644 --- a/constructs/incident-trigger.mdx +++ b/constructs/incident-trigger.mdx @@ -71,6 +71,7 @@ The status page service that this incident will be associated with. When a check **Usage:** +{/* typecheck-wrap: StatusPageService */} ```ts highlight={6} const searchService = new StatusPageService("search-service", { name: "Search Service", diff --git a/constructs/incidentio-alert-channel.mdx b/constructs/incidentio-alert-channel.mdx index fe66ac5e..37bc7568 100644 --- a/constructs/incidentio-alert-channel.mdx +++ b/constructs/incidentio-alert-channel.mdx @@ -70,6 +70,7 @@ We have [handlebar helpers and variables](/integrations/alerts/webhooks/#using-v Here's an example payload, using the default one that we provide: +{/* typecheck-wrap: IncidentioAlertChannel */} ```ts highlight={5-26} new IncidentioAlertChannel('incidentio-channel-1', { name: 'ACME alerts', diff --git a/constructs/including-checks.mdx b/constructs/including-checks.mdx index c082dafa..1d56ca57 100644 --- a/constructs/including-checks.mdx +++ b/constructs/including-checks.mdx @@ -24,8 +24,11 @@ Here are some best practices: 2. Store any Checkly related Checks inside a `__checks__` folder. This neatly indicates where your Checks are organized. 3. Use multiple `__checks__` folders throughout your code base, near the functionality it should be checking. -```ts checkly.config.ts highlight={4} +{/* typecheck-wrap */} +```ts checkly.config.ts highlight={6} const config = defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { // A glob pattern that matches the Checks inside your repo. checkMatch: "**/__checks__/**/*.check.ts", @@ -52,8 +55,11 @@ again the new `logicalId` will trigger a deletion of the "old" Check and a creat any historical metrics. -```ts checkly.config.ts highlight={7} +{/* typecheck-wrap */} +```ts checkly.config.ts highlight={9} const config = defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { checkMatch: "**/__checks__/**/*.check.ts", browserChecks: { @@ -65,6 +71,7 @@ const config = defineConfig({ }) ``` +{/* typecheck-wrap: CheckGroupV2 */} ```ts group.check.ts highlight={6} const group = new CheckGroupV2("api-monitoring-group", { name: "Browser Check Monitoring Group", @@ -87,8 +94,11 @@ to prevent loading the wrong check type. For example using `browserChecks.testMa in all checks created as Browser checks. -```ts checkly.config.ts highlight={7} +{/* typecheck-wrap */} +```ts checkly.config.ts highlight={9} const config = defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { checkMatch: "**/__checks__/**/*.check.ts", // A glob pattern matches any Playwright .spec.ts files @@ -100,6 +110,7 @@ const config = defineConfig({ }) ``` +{/* typecheck-wrap: CheckGroupV2 */} ```ts group.check.ts highlight={6} const group = new CheckGroupV2("api-multistep-group", { name: "API Multistep Monitoring Group", diff --git a/constructs/maintenance-window.mdx b/constructs/maintenance-window.mdx index 510cfe60..a27c9b81 100644 --- a/constructs/maintenance-window.mdx +++ b/constructs/maintenance-window.mdx @@ -63,6 +63,7 @@ A name for the maintenance window that will be displayed in the Checkly dashboar Usage: +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={2} new MaintenanceWindow("my-maintenance", { name: "Weekly Database Backup", @@ -79,6 +80,7 @@ Tags that filter which checks are affected by this maintenance window. Checks wi **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={3} new MaintenanceWindow("my-maintenance", { name: "API Maintenance", @@ -99,6 +101,7 @@ Start date and time for the maintenance window in UTC (ISO 8601 timestamp). **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={3} new MaintenanceWindow("my-maintenance", { name: "Database Maintenance", @@ -116,6 +119,7 @@ End date and time for the maintenance window in UTC (ISO 8601 timestamp). **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={4} new MaintenanceWindow("my-maintenance", { name: "Database Maintenance", @@ -133,6 +137,7 @@ Repeat interval from the first occurrence. Used with `repeatUnit` to create recu **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={3} new MaintenanceWindow("recurring-maintenance", { name: "Weekly Maintenance", @@ -151,6 +156,7 @@ Repeat strategy that defines the time unit for recurring maintenance windows (`D **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={4} new MaintenanceWindow('recurring-maintenance', { name: "Bi-weekly Maintenance", @@ -164,6 +170,7 @@ new MaintenanceWindow('recurring-maintenance', { +{/* typecheck-wrap: MaintenanceWindow */} ```ts Daily Maintenance new MaintenanceWindow("daily-updates", { name: "Daily Database Sync", @@ -175,6 +182,7 @@ new MaintenanceWindow("daily-updates", { }) ``` +{/* typecheck-wrap: MaintenanceWindow */} ```ts Weekly Maintenance new MaintenanceWindow("weekly-updates", { name: "Weekly System Updates", @@ -186,6 +194,7 @@ new MaintenanceWindow("weekly-updates", { }) ``` +{/* typecheck-wrap: MaintenanceWindow */} ```ts Monthly Maintenance new MaintenanceWindow("monthly-db", { name: "Monthly Database Maintenance", @@ -207,6 +216,7 @@ When to stop repeating the maintenance window (ISO 8601 timestamp in UTC). If no **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={5} new MaintenanceWindow("limited-recurring", { name: "Limited Time Maintenance", @@ -227,6 +237,7 @@ The named [IANA time zone](https://en.wikipedia.org/wiki/List_of_tz_database_tim **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={4} new MaintenanceWindow("nightly-maintenance", { name: "Nightly Maintenance", @@ -251,6 +262,7 @@ Pause every check in the account during the maintenance window, regardless of `t **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={3} new MaintenanceWindow("platform-migration", { name: "Platform Migration", @@ -267,6 +279,7 @@ Tags that filter which checks have their alerts silenced during the maintenance **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={3} new MaintenanceWindow("degraded-api", { name: "Expected API Degradation", @@ -283,6 +296,7 @@ Silence alerts for every check in the account during the maintenance window, reg **Usage:** +{/* typecheck-wrap: MaintenanceWindow */} ```ts highlight={3} new MaintenanceWindow("quiet-period", { name: "Quiet Period", @@ -298,6 +312,7 @@ new MaintenanceWindow("quiet-period", { + {/* typecheck-wrap: MaintenanceWindow */} ```ts new MaintenanceWindow("database-maintenance", { name: "Monthly Database Maintenance", @@ -312,6 +327,7 @@ new MaintenanceWindow("quiet-period", { + {/* typecheck-wrap: MaintenanceWindow */} ```ts new MaintenanceWindow("system-updates", { name: "Weekly System Updates", @@ -326,6 +342,7 @@ new MaintenanceWindow("quiet-period", { + {/* typecheck-wrap */} ```ts // For immediate one-time maintenance const now = new Date() @@ -342,6 +359,7 @@ new MaintenanceWindow("quiet-period", { + {/* typecheck-wrap: MaintenanceWindow */} ```ts // API service maintenance new MaintenanceWindow("api-maintenance", { diff --git a/constructs/msteams-alert-channel.mdx b/constructs/msteams-alert-channel.mdx index 484b96d3..ba1be7a7 100644 --- a/constructs/msteams-alert-channel.mdx +++ b/constructs/msteams-alert-channel.mdx @@ -178,6 +178,7 @@ We have [handlebar helpers and variables](/integrations/alerts/webhooks/#using-v Here's an example payload, using the default one that we provide: +{/* typecheck-wrap: MSTeamsAlertChannel */} ```ts highlight={4-120} expandable new MSTeamsAlertChannel('msteams-channel-01', { name: 'ACME alerts', diff --git a/constructs/multistep-check.mdx b/constructs/multistep-check.mdx index 728836b9..37f5795a 100644 --- a/constructs/multistep-check.mdx +++ b/constructs/multistep-check.mdx @@ -269,9 +269,11 @@ Friendly name for your multistep check that will be displayed in the Checkly das **Usage:** +{/* typecheck-wrap: MultiStepCheck */} ```ts highlight={2} new MultiStepCheck("my-multistep", { - name: "Complete User Journey Test" + name: "Complete User Journey Test", + /* More options... */ }) ``` @@ -283,6 +285,7 @@ The Checkly runtime version used to execute the Multistep Check. Runtimes are ma Multistep checks require runtime `2023.09` or later. Usage: +{/* typecheck-wrap: MultiStepCheck */} ```ts highlight={3} new MultiStepCheck("my-multistep", { name: 'My Multistep Check', @@ -317,6 +320,7 @@ new MultiStepCheck("my-multistep", { Array of public location codes where the multistep check should run. Multiple locations provide geographic coverage and user experience insights. Usage: +{/* typecheck-wrap: MultiStepCheck */} ```ts highlight={3} new MultiStepCheck("global-check", { name: "Global Multistep Check", @@ -330,6 +334,7 @@ Examples: +{/* typecheck-wrap: MultiStepCheck */} ```ts // Worldwide API testing new MultiStepCheck("global-journey", { @@ -348,6 +353,7 @@ new MultiStepCheck("global-journey", { +{/* typecheck-wrap: MultiStepCheck */} ```ts // European user focus new MultiStepCheck("eu-workflow", { diff --git a/constructs/overview.mdx b/constructs/overview.mdx index edb026fd..0137d551 100644 --- a/constructs/overview.mdx +++ b/constructs/overview.mdx @@ -133,8 +133,9 @@ Find a full reference of all check properties in [the `ApiCheck` construct](/con Assigning a `logicalId` is crucial when creating a construct. Remember the following rules when creating and updating constructs: 1. Every construct needs to have a `logicalId`. This is the first argument when instantiating a class, i.e. +{/* typecheck-wrap: ApiCheck */} ```ts -const check = new ApiCheck('my-logical-id', { name: 'My API check' }) +const check = new ApiCheck('my-logical-id', { name: 'My API check', /* More options... */ }) ``` 2. Every `logicalId` needs to be unique within the scope of a `Project`. 3. A `Project` also has a `logicalId`. This needs to be unique within the scope of the Checkly account. diff --git a/constructs/phone-call-alert-channel.mdx b/constructs/phone-call-alert-channel.mdx index ea39cdc3..fdfb810f 100644 --- a/constructs/phone-call-alert-channel.mdx +++ b/constructs/phone-call-alert-channel.mdx @@ -54,6 +54,7 @@ Each `PhoneCallAlertChannel` supports only one phone number. Phone numbers need We only support phone numbers from certain [countries and regions](/integrations/alerts/phone-calls/#supported-countries-and-regions). +{/* typecheck-wrap: PhoneCallAlertChannel */} ```ts highlight={2} new PhoneCallAlertChannel('call-channel-1', { phoneNumber: '+31061234567890', diff --git a/constructs/playwright-check.mdx b/constructs/playwright-check.mdx index 8500c761..aa495199 100644 --- a/constructs/playwright-check.mdx +++ b/constructs/playwright-check.mdx @@ -106,6 +106,7 @@ The path to the Playwright configuration file (`playwright.config.js/ts`) which **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={3} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -123,6 +124,7 @@ Checkly defaults to using npm, but automatically detects other package managers **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={4} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -139,6 +141,7 @@ The command to execute Playwright tests when running `npx checkly test` or runni **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={4} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -163,6 +166,7 @@ The defined projects to run from your Playwright configuration. +{/* typecheck-wrap: PlaywrightCheck */} ```ts Single project highlight={4} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -171,6 +175,7 @@ new PlaywrightCheck("critical-e2e-monitor", { }) ``` +{/* typecheck-wrap: PlaywrightCheck */} ```ts Multiple projects highlight={4} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -195,6 +200,7 @@ Tests matching any of these tags will be executed. +{/* typecheck-wrap: PlaywrightCheck */} ```ts Single project highlight={4} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -203,6 +209,7 @@ new PlaywrightCheck("critical-e2e-monitor", { }) ``` +{/* typecheck-wrap: PlaywrightCheck */} ```ts Multiple projects highlight={4} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -223,6 +230,7 @@ Defines the glob patterns for files and directories that should be included when **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={4} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -299,6 +307,7 @@ Friendly name for your Playwright Check Suite that will be displayed in the Chec **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={2} new PlaywrightCheck("critical-e2e-monitor", { name: "Critical E2E Monitor", @@ -314,6 +323,7 @@ How often the Playwright Check Suite should run. Use the `Frequency` enum to set **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={4} new PlaywrightCheck("my-pwt-check-suite", { name: "My Playwright Check Suite", @@ -326,6 +336,7 @@ new PlaywrightCheck("my-pwt-check-suite", { +{/* typecheck-wrap: PlaywrightCheck */} ```ts High Frequency // For critical user journeys new PlaywrightCheck("my-pwt-check-suite", { @@ -336,6 +347,7 @@ new PlaywrightCheck("my-pwt-check-suite", { }) ``` +{/* typecheck-wrap: PlaywrightCheck */} ```ts Standard Frequency // For regular monitoring new PlaywrightCheck("my-pwt-check-suite", { @@ -357,6 +369,7 @@ Array of public location codes where the Playwright Check Suite should run. Mult **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={4} new PlaywrightCheck("my-pwt-check-suite", { name: "My Playwright Check Suite", @@ -369,6 +382,7 @@ new PlaywrightCheck("my-pwt-check-suite", { +{/* typecheck-wrap: PlaywrightCheck */} ```ts Global Coverage // Comprehensive global monitoring new PlaywrightCheck("global-pwt-check-suite", { @@ -384,6 +398,7 @@ new PlaywrightCheck("global-pwt-check-suite", { }) ``` +{/* typecheck-wrap: PlaywrightCheck */} ```ts Regional Focus // Focus on specific regions new PlaywrightCheck("europe-pwt-check-suite", { @@ -404,6 +419,7 @@ Whether the Playwright Check Suite is enabled and will run according to its sche **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={4} new PlaywrightCheck("disabled-pwt-check-suite", { name: "Disabled Playwright Check Suite", @@ -420,6 +436,7 @@ Array of Checkly tags to organize and categorize your Playwright Check Suite in **Usage:** +{/* typecheck-wrap: PlaywrightCheck */} ```ts highlight={4} new PlaywrightCheck("my-check-suite", { name: "My Playwright Check Suite", @@ -432,6 +449,7 @@ new PlaywrightCheck("my-check-suite", { +{/* typecheck-wrap: PlaywrightCheck */} ```ts Priority Tags new PlaywrightCheck("my-check-suite", { name: "My Playwright Check Suite", @@ -440,6 +458,7 @@ new PlaywrightCheck("my-check-suite", { }) ``` +{/* typecheck-wrap: PlaywrightCheck */} ```ts Environment Tags new PlaywrightCheck("staging-check-suite", { name: "Staging Playwright Check Suite", @@ -507,6 +526,7 @@ new PlaywrightCheck("user-flow-pwt-check-suite", { }) ``` +{/* typecheck-wrap: PlaywrightCheck */} ```ts Environment settings new PlaywrightCheck("feature-test", { name: "Feature Flag Test", @@ -531,6 +551,7 @@ new PlaywrightCheck("feature-test", { +{/* typecheck-wrap: PlaywrightCheck */} ```ts Multi-browser Support const playwrightChecks = new PlaywrightCheck("multi-browser-check", { name: "Multi-browser check suite", @@ -541,6 +562,7 @@ const playwrightChecks = new PlaywrightCheck("multi-browser-check", { }) ``` +{/* typecheck-wrap: PlaywrightCheck */} ```ts Project-dependency Support // Often, it makes sense to define different Playwright projects // in your `playwright.config` and make them depend on each other diff --git a/constructs/private-location.mdx b/constructs/private-location.mdx index 253a2039..6b8fe2b9 100644 --- a/constructs/private-location.mdx +++ b/constructs/private-location.mdx @@ -74,6 +74,7 @@ Friendly name for your private location that will be displayed in the Checkly da **Usage:** +{/* typecheck-wrap: PrivateLocation */} ```ts new PrivateLocation("my-location", { name: "Corporate Data Center", @@ -88,6 +89,7 @@ Unique slug identifier for your private location. This must be unique across you **Usage:** +{/* typecheck-wrap: PrivateLocation */} ```ts new PrivateLocation("my-location", { name: "My Location", @@ -100,6 +102,7 @@ new PrivateLocation("my-location", { +{/* typecheck-wrap: PrivateLocation */} ```ts // Descriptive and stable slugs new PrivateLocation("corp-vpc-east", { @@ -121,6 +124,7 @@ new PrivateLocation("datacenter-west", { +{/* typecheck-wrap: PrivateLocation */} ```ts // Too generic or likely to change new PrivateLocation("location-1", { @@ -147,6 +151,7 @@ The `slugName` must be unique across your entire Checkly account and cannot be c Octicon name to visually distinguish the location in the Checkly UI. Choose icons that represent your infrastructure type or purpose. Usage: +{/* typecheck-wrap: PrivateLocation */} ```ts new PrivateLocation("my-location", { name: "Database Zone", @@ -162,6 +167,7 @@ new PrivateLocation("my-location", { Proxy URL for outgoing HTTP calls from this private location. Use when your infrastructure requires all external traffic to go through a corporate proxy. Usage: +{/* typecheck-wrap: PrivateLocation */} ```ts new PrivateLocation('corporate-location', { name: 'Corporate Network', @@ -177,6 +183,7 @@ Reference private locations by using their construct reference or by slug names +{/* typecheck-wrap: PrivateLocation */} ```ts const privateLocationVpcEast = new PrivateLocation("corp-vpc-east", { name: "Corporate VPC East", @@ -197,6 +204,7 @@ new ApiCheck("existing-location-reference", { +{/* typecheck-wrap: ApiCheck */} ```ts new ApiCheck("existing-location-check", { name: "Check Using Existing Location", @@ -211,6 +219,7 @@ new ApiCheck("existing-location-check", { +{/* typecheck-wrap: PrivateLocation */} ```ts // Combine new and existing private locations const newLocation = new PrivateLocation("new-location", { @@ -241,6 +250,7 @@ new ApiCheck("mixed-locations-check", { +{/* typecheck-wrap: PrivateLocation */} ```ts new PrivateLocation("corp-proxy-location", { name: "Corporate Network with Proxy", @@ -252,6 +262,7 @@ new PrivateLocation("corp-proxy-location", { +{/* typecheck-wrap: PrivateLocation */} ```ts new PrivateLocation("secure-proxy-location", { name: "Secure Corporate Proxy", @@ -263,6 +274,7 @@ new PrivateLocation("secure-proxy-location", { +{/* typecheck-wrap: PrivateLocation */} ```ts new PrivateLocation("auth-proxy-location", { name: "Authenticated Proxy Location", @@ -316,6 +328,7 @@ When `proxyUrl` is configured, all HTTP calls from API checks running in this pr + {/* typecheck-wrap: PrivateLocation */} ```ts const eastDatacenter = new PrivateLocation("dc-east", { name: "East Coast Datacenter", @@ -358,6 +371,7 @@ When `proxyUrl` is configured, all HTTP calls from API checks running in this pr + {/* typecheck-wrap: PrivateLocation */} ```ts const devEnvironment = new PrivateLocation("dev-env", { name: "Development Environment", @@ -395,6 +409,7 @@ When `proxyUrl` is configured, all HTTP calls from API checks running in this pr + {/* typecheck-wrap: PrivateLocation */} ```ts const corporateLocation = new PrivateLocation("corporate-with-proxy", { name: "Corporate Network with Proxy", diff --git a/constructs/project.mdx b/constructs/project.mdx index c57ca462..f72a8692 100644 --- a/constructs/project.mdx +++ b/constructs/project.mdx @@ -82,6 +82,7 @@ Friendly name for your project that will be displayed in the Checkly dashboard a **Usage:** +{/* typecheck-wrap */} ```ts highlight={2} export default defineConfig({ projectName: 'Website Monitoring', @@ -98,6 +99,7 @@ Unique identifier for this project that should remain stable across deployments. **Usage:** +{/* typecheck-wrap */} ```ts highlight={2} export default defineConfig({ logicalId: 'website-monitoring-prod', @@ -118,6 +120,7 @@ Optional URL to a Git repository for documentation and team collaboration purpos **Usage:** +{/* typecheck-wrap */} ```ts highlight={2} export default defineConfig({ repoUrl: 'https://github.com/acme/website', @@ -134,6 +137,7 @@ Defaults for CLI commands like `checkly test` and `checkly trigger`. **Usage:** +{/* typecheck-wrap */} ```ts highlight={4-7} export default defineConfig({ projectName: "Website Monitoring", @@ -165,6 +169,7 @@ Top-level defaults for all checks in this project. Individual checks and groups **Usage:** +{/* typecheck-wrap */} ```ts highlight={5-13} export default defineConfig({ projectName: "Website Monitoring", @@ -217,6 +222,7 @@ Whether the checks and monitors are enabled and will run according to its schedu **Usage:** +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -235,6 +241,7 @@ Default alert channels for all checks and monitors. **Usage:** +{/* typecheck-wrap: SmsAlertChannel */} ```ts highlight={9} const smsAlertChannel = new SmsAlertChannel("sms-alert-channel", { phoneNumber: "+1234567890", @@ -257,6 +264,7 @@ Glob pattern where the CLI looks for files containing Check constructs, i.e. all **Usage:** +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -277,6 +285,7 @@ Environment variables available to the check script and monitors. **Usage:** +{/* typecheck-wrap */} ```ts highlight={5-10} export default defineConfig({ projectName: "Website Monitoring", @@ -300,6 +309,7 @@ Default frequency at which the checks and monitors are executed. **Usage:** +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -322,6 +332,7 @@ Directories to ignore when looking for check files. **Usage:** +{/* typecheck-wrap */} ```ts highlight={6} export default defineConfig({ projectName: "Website Monitoring", @@ -338,6 +349,7 @@ export default defineConfig({ Array of public location codes where the URL monitor should run from. Multiple locations provide geographic coverage. +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -360,6 +372,7 @@ Determine if any notifications will be sent out when a check fails and/or recove **Usage:** +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -378,6 +391,7 @@ Global configuration options for the Playwright Test Runner use in [Browser Chec **Usage:** +{/* typecheck-wrap */} ```ts highlight={5-16} export default defineConfig({ projectName: "Website Monitoring", @@ -411,6 +425,7 @@ Playwright config path to be used during [Playwright Check Suite](/detect/synthe **Usage:** +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -429,6 +444,7 @@ Private Locations to run your monitors and checks from. **Usage:** +{/* typecheck-wrap: PrivateLocation */} ```ts highlight={12} const datacenterLocation = new PrivateLocation("datacenter-east-1", { name: "East Coast Datacenter", @@ -456,6 +472,7 @@ Set a retry policy for your checks and monitors. [Use `RetryStrategyBuilder`](/c **Usage:** +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -480,6 +497,7 @@ The runtime version used to execute checks and monitors. **Usage:** +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -500,6 +518,7 @@ The tags assigned to the checks and monitors. **Usage:** +{/* typecheck-wrap */} ```ts highlight={5} export default defineConfig({ projectName: "Website Monitoring", @@ -526,6 +545,7 @@ If your project doesn't require specific configuration and you want to quickly t **Example:** +{/* typecheck-wrap */} ```ts highlight={6} export default defineConfig({ projectName: "Website Monitoring", @@ -554,6 +574,7 @@ If your project doesn't require specific configuration and you want to quickly t **Example:** +{/* typecheck-wrap */} ```ts highlight={6} export default defineConfig({ projectName: "API Monitoring", @@ -574,6 +595,7 @@ export default defineConfig({ **Usage:** +{/* typecheck-wrap */} ```ts highlight={5-14} export default defineConfig({ projectName: "Website Monitoring", @@ -640,6 +662,7 @@ export default defineConfig({ + {/* typecheck-wrap */} ```ts export default defineConfig({ projectName: "Acme Website", diff --git a/constructs/retry-strategy.mdx b/constructs/retry-strategy.mdx index 1df6e858..fdd52221 100644 --- a/constructs/retry-strategy.mdx +++ b/constructs/retry-strategy.mdx @@ -92,6 +92,7 @@ Disables all retries for a check. When a check fails, it immediately triggers an **Usage:** +{/* typecheck-wrap: ApiCheck */} ```ts highlight={4} // Critical endpoint that should alert immediately new ApiCheck("critical-endpoint", { @@ -112,6 +113,7 @@ Performs exactly one retry after a failure. **Usage:** +{/* typecheck-wrap: ApiCheck */} ```ts highlight={4-6} new ApiCheck("single-retry-check", { name: "Single Retry Check", @@ -135,6 +137,7 @@ Time between retries with five seconds `baseBackoffSeconds` and three retries: ` +{/* typecheck-wrap: ApiCheck */} ```ts highlight={4-8} // Stable API with predictable retry pattern new ApiCheck("stable-api", { @@ -152,6 +155,7 @@ new ApiCheck("stable-api", { +{/* typecheck-wrap: ApiCheck */} ```ts highlight={4-8} // Database connectivity with consistent intervals new ApiCheck("database-health", { @@ -182,6 +186,7 @@ Time between retries with five seconds `baseBackoffSeconds` and three retries: ` +{/* typecheck-wrap: ApiCheck */} ```ts highlight={4-8} // API with gradual backoff strategy new ApiCheck("gradual-backoff", { @@ -199,6 +204,7 @@ new ApiCheck("gradual-backoff", { +{/* typecheck-wrap: ApiCheck */} ```ts highlight={4-8} // Service that might need time to recover new ApiCheck("recovering-service", { @@ -229,6 +235,7 @@ Time between retries with five seconds `baseBackoffSeconds` and three retries: ` +{/* typecheck-wrap: ApiCheck */} ```ts highlight={4-9} // Service that might be overloaded new ApiCheck("overloaded-api", { @@ -247,6 +254,7 @@ new ApiCheck("overloaded-api", { +{/* typecheck-wrap: ApiCheck */} ```ts highlight={4-9} // API with rate limiting new ApiCheck("rate-limited-api", { @@ -275,6 +283,7 @@ Time to wait before the first retry attempt. Also used as the base value for cal **Usage:** +{/* typecheck-wrap */} ```ts highlight={3,8,13} // Quick retries for fast services RetryStrategyBuilder.fixedStrategy({ @@ -298,6 +307,7 @@ Maximum number of retry attempts after the initial failure. The total number of **Usage:** +{/* typecheck-wrap */} ```ts highlight={2} RetryStrategyBuilder.linearStrategy({ maxRetries: 3, // 3 retry attempts after initial failure @@ -312,6 +322,7 @@ Maximum total time to spend on all retry attempts. If the calculated retry sched **Usage:** +{/* typecheck-wrap */} ```ts highlight={2} RetryStrategyBuilder.exponentialStrategy({ maxDurationSeconds: 300, // Stop retrying after 5 minutes total @@ -324,6 +335,7 @@ Whether retry attempts should run from the same region as the original failed ch **Usage:** +{/* typecheck-wrap */} ```ts highlight={2} RetryStrategyBuilder.linearStrategy({ sameRegion: false, // Try different regions for retries @@ -342,6 +354,7 @@ Apply the retry strategy only when the failure cause matches the specified condi **Usage:** +{/* typecheck-wrap */} ```ts highlight={3} RetryStrategyBuilder.fixedStrategy({ maxRetries: 3, @@ -503,6 +516,7 @@ Currently supports `'NETWORK_ERROR'` for `ApiCheck` and `UrlMonitor` constructs + {/* typecheck-wrap */} ```ts // For stable APIs - minimal retries const stableApiRetry = RetryStrategyBuilder.fixedStrategy({ @@ -521,6 +535,7 @@ Currently supports `'NETWORK_ERROR'` for `ApiCheck` and `UrlMonitor` constructs + {/* typecheck-wrap */} ```ts // Critical endpoints - fail fast to alert quickly const criticalRetry = RetryStrategyBuilder.fixedStrategy({ @@ -539,6 +554,7 @@ Currently supports `'NETWORK_ERROR'` for `ApiCheck` and `UrlMonitor` constructs + {/* typecheck-wrap */} ```ts // Browser checks - longer backoff due to complexity const browserRetry = RetryStrategyBuilder.linearStrategy({ diff --git a/constructs/slack-alert-channel.mdx b/constructs/slack-alert-channel.mdx index 5158ecfd..312f6cfc 100644 --- a/constructs/slack-alert-channel.mdx +++ b/constructs/slack-alert-channel.mdx @@ -52,6 +52,7 @@ const slackChannel = new SlackAlertChannel('slack-channel-1', { The Slack incoming webhook URL where Checkly will send alert notifications. +{/* typecheck-wrap: SlackAlertChannel */} ```ts highlight={2} new SlackAlertChannel('slack-channel-1', { url: new URL('https://hooks.slack.com/services/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'), diff --git a/constructs/slack-app-alert-channel.mdx b/constructs/slack-app-alert-channel.mdx index b18b7135..7724eb73 100644 --- a/constructs/slack-app-alert-channel.mdx +++ b/constructs/slack-app-alert-channel.mdx @@ -50,6 +50,7 @@ const slackAppChannel = new SlackAppAlertChannel('slack-channel-1', { The Slack channels to alert. Can also include DM handles, e.g. "@John Doe" +{/* typecheck-wrap: SlackAppAlertChannel */} ```ts highlight={2} new SlackAppAlertChannel('slack-channel-1', { slackChannels: ['#ops','@John Doe'] diff --git a/constructs/sms-alert-channel.mdx b/constructs/sms-alert-channel.mdx index 692fd770..a4f2caf9 100644 --- a/constructs/sms-alert-channel.mdx +++ b/constructs/sms-alert-channel.mdx @@ -55,6 +55,7 @@ Each `SmsAlertChannel` supports only one phone number. Phone numbers need to be We only support phone numbers from certain [countries and regions](/integrations/alerts/sms#supported-countries-and-regions). +{/* typecheck-wrap: SmsAlertChannel */} ```ts highlight={3} new SmsAlertChannel('sms-channel-1', { name: 'Ops on-call', diff --git a/constructs/ssl-monitor.mdx b/constructs/ssl-monitor.mdx index 324aa296..22198294 100644 --- a/constructs/ssl-monitor.mdx +++ b/constructs/ssl-monitor.mdx @@ -112,6 +112,7 @@ SSL connection configuration that defines the target host and all TLS-specific o **Usage:** +{/* typecheck-wrap: SslMonitor */} ```ts new SslMonitor("my-ssl-monitor", { name: "Example SSL Monitor", @@ -141,6 +142,7 @@ TLS handshake time in milliseconds at or above which the monitor is marked as de **Usage:** +{/* typecheck-wrap: SslMonitor */} ```ts highlight={3} new SslMonitor("my-ssl", { name: "Example SSL", @@ -159,6 +161,7 @@ TLS handshake time in milliseconds at or above which the monitor is marked as fa **Usage:** +{/* typecheck-wrap: SslMonitor */} ```ts highlight={4} new SslMonitor("my-ssl", { name: "Example SSL", @@ -345,6 +348,7 @@ Learn more in our docs on [Assertions](/detect/assertions). Friendly name for your SSL Monitor, displayed in the Checkly dashboard and used in notifications. +{/* typecheck-wrap: SslMonitor */} ```ts highlight={2} new SslMonitor("my-ssl-monitor", { name: "Homepage Certificate", @@ -356,6 +360,7 @@ new SslMonitor("my-ssl-monitor", { How often the SSL Monitor should run. Use the `Frequency` enum to set the check interval. +{/* typecheck-wrap: SslMonitor */} ```ts highlight={3} new SslMonitor("my-ssl-monitor", { name: "Homepage Certificate", @@ -370,6 +375,7 @@ new SslMonitor("my-ssl-monitor", { Array of [public location codes](/concepts/locations/#public-locations) where the monitor should run from. Multiple locations provide geographic coverage. +{/* typecheck-wrap: SslMonitor */} ```ts highlight={3} new SslMonitor("global-ssl", { name: "Global Certificate Monitor", @@ -382,6 +388,7 @@ new SslMonitor("global-ssl", { Whether the SSL Monitor is enabled and will run according to its schedule. +{/* typecheck-wrap: SslMonitor */} ```ts highlight={3} new SslMonitor("my-ssl-monitor", { name: "Homepage Certificate", diff --git a/constructs/status-page-service.mdx b/constructs/status-page-service.mdx index cfc6aafd..467ac894 100644 --- a/constructs/status-page-service.mdx +++ b/constructs/status-page-service.mdx @@ -96,6 +96,7 @@ Display name for the service on the status page. This name appears in the status **Usage:** +{/* typecheck-wrap: StatusPageService */} ```ts highlight={2} new StatusPageService("api-service", { name: "API Service", @@ -226,6 +227,7 @@ new StatusPage("simple-status", { StatusPageService instances can be reused across multiple status pages: +{/* typecheck-wrap: StatusPageService */} ```ts // Define services once const apiService = new StatusPageService("api-service", { diff --git a/constructs/status-page-v3-automation-rule.mdx b/constructs/status-page-v3-automation-rule.mdx index 8965d73e..2584524a 100644 --- a/constructs/status-page-v3-automation-rule.mdx +++ b/constructs/status-page-v3-automation-rule.mdx @@ -52,6 +52,7 @@ A failing check matches this rule when it, or its group, carries any of these ta **Usage:** +{/* typecheck-wrap: StatusPageV3AutomationRule */} ```ts highlight={4} new StatusPageV3AutomationRule("api-outage-rule", { statusPage, @@ -87,6 +88,7 @@ The impact set on the component while the incident is open: `'UNDER_MAINTENANCE' **Usage:** +{/* typecheck-wrap: StatusPageV3AutomationRule */} ```ts highlight={5-8} new StatusPageV3AutomationRule("api-outage-rule", { statusPage, diff --git a/constructs/status-page-v3-component.mdx b/constructs/status-page-v3-component.mdx index 0652a9f1..1c1384f9 100644 --- a/constructs/status-page-v3-component.mdx +++ b/constructs/status-page-v3-component.mdx @@ -40,6 +40,7 @@ The page this component belongs to. A component belongs to exactly one page and **Usage:** +{/* typecheck-wrap: StatusPageV3Component */} ```ts highlight={2} new StatusPageV3Component("api-component", { statusPage, @@ -62,6 +63,7 @@ Position among its siblings; lower comes first. **Usage:** +{/* typecheck-wrap: StatusPageV3Component */} ```ts highlight={3} new StatusPageV3Component("backend-group", { statusPage, @@ -85,6 +87,7 @@ The `GROUP` component to nest this component under. Must be on the same status p **Usage:** +{/* typecheck-wrap: StatusPageV3Component */} ```ts highlight={4} new StatusPageV3Component("api-component", { statusPage, @@ -103,6 +106,7 @@ Unlike v2 services, a component belongs to one status page. It cannot be shared Use `StatusPageV3Component.fromId()` to point an [automation rule](/constructs/status-page-v3-automation-rule) or a `parent` at a component created in the UI: +{/* typecheck-wrap */} ```ts const cdn = StatusPageV3Component.fromId("790f145a-6ce9-4d94-b7b2-a92e0e2c6a1a") ``` diff --git a/constructs/status-page-v3.mdx b/constructs/status-page-v3.mdx index 0a01b712..3d887133 100644 --- a/constructs/status-page-v3.mdx +++ b/constructs/status-page-v3.mdx @@ -100,6 +100,7 @@ Name of the status page, shown in the header and browser title. **Usage:** +{/* typecheck-wrap: StatusPageV3 */} ```ts highlight={2} new StatusPageV3("company-status", { name: "Company Status", @@ -126,6 +127,7 @@ Custom domain for your status page (e.g., `status.example.com`). Requires DNS co **Usage:** +{/* typecheck-wrap: StatusPageV3 */} ```ts highlight={4} new StatusPageV3("company-status", { name: "Company Status", @@ -194,6 +196,7 @@ Custom theme colors must be part of your plan. **Usage:** +{/* typecheck-wrap: StatusPageV3 */} ```ts themeColors: { light: { diff --git a/constructs/status-page.mdx b/constructs/status-page.mdx index 917decd1..f2716017 100644 --- a/constructs/status-page.mdx +++ b/constructs/status-page.mdx @@ -103,6 +103,7 @@ Name of the status page displayed in the header and browser title. **Usage:** +{/* typecheck-wrap: StatusPage */} ```ts highlight={2} new StatusPage("company-status", { name: "Company Status Page", @@ -119,6 +120,7 @@ Array of card objects that organize services into logical groups on the status p **Usage:** +{/* typecheck-wrap: StatusPage */} ```ts highlight={3-8} new StatusPage("company-status", { name: "Company Status", @@ -143,6 +145,7 @@ new StatusPage("company-status", { +{/* typecheck-wrap: StatusPageService */} ```ts Functional Organization const webAppService = new StatusPageService("web-app", { name: "Web Application" }) const mobileApiService = new StatusPageService("mobile-api", { name: "Mobile API" }) @@ -164,6 +167,7 @@ new StatusPage("functional-status", { }) ``` +{/* typecheck-wrap: StatusPageService */} ```ts Team Organization const frontendAppService = new StatusPageService("frontend", { name: "Frontend App" }) const backendApiService = new StatusPageService("backend", { name: "Backend API" }) @@ -189,6 +193,7 @@ new StatusPage("team-status", { }) ``` +{/* typecheck-wrap: StatusPageService */} ```ts Priority Organization const coreApiService = new StatusPageService("core-api", { name: "Core API" }) const authService = new StatusPageService("auth", { name: "Authentication" }) @@ -238,6 +243,7 @@ Custom domain for your status page (e.g., `status.example.com`). Requires DNS co **Usage:** +{/* typecheck-wrap: StatusPage */} ```ts highlight={4} new StatusPage("company-status", { name: "Company Status", @@ -256,6 +262,7 @@ URL to logo image displayed in the status page header. Must be publicly accessib **Usage:** +{/* typecheck-wrap: StatusPage */} ```ts highlight={3} new StatusPage("company-status", { name: "Company Status", @@ -272,6 +279,7 @@ URL to redirect users when they click the logo. Typically your main website or s **Usage:** +{/* typecheck-wrap: StatusPage */} ```ts highlight={4} new StatusPage("company-status", { name: "Company Status", @@ -290,6 +298,7 @@ URL to favicon image displayed in browser tabs. Must be publicly accessible. **Usage:** +{/* typecheck-wrap: StatusPage */} ```ts highlight={3} new StatusPage("company-status", { name: "Company Status", @@ -307,6 +316,7 @@ Default color theme for the status page. Options: 'LIGHT', 'DARK', or 'AUTO' (fo **Usage:** +{/* typecheck-wrap: StatusPage */} ```ts highlight={3} new StatusPage("company-status", { name: "Company Status", diff --git a/constructs/tcp-monitor.mdx b/constructs/tcp-monitor.mdx index 895b5bbc..76794ed5 100644 --- a/constructs/tcp-monitor.mdx +++ b/constructs/tcp-monitor.mdx @@ -103,6 +103,7 @@ TCP connection configuration that defines the hostname, port, and optional data **Usage:** +{/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("tcp-monitor", { name: "Database TCP Check", @@ -129,6 +130,7 @@ new TcpMonitor("tcp-monitor", { +{/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("database-check", { name: "Database Connectivity", @@ -144,6 +146,7 @@ new TcpMonitor("database-check", { +{/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("redis-ping", { name: "Redis PING Test", @@ -162,6 +165,7 @@ new TcpMonitor("redis-ping", { +{/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("ipv6-service", { name: "IPv6 Service Check", @@ -184,6 +188,7 @@ new TcpMonitor("ipv6-service", { Response time threshold in milliseconds for marking the monitor as degraded (warning state). Usage: +{/* typecheck-wrap: TcpMonitor */} ```ts highlight={3} new TcpMonitor("tiered-monitoring", { name: "Tiered Monitoring", @@ -197,6 +202,7 @@ new TcpMonitor("tiered-monitoring", { ``` Examples: +{/* typecheck-wrap: TcpMonitor */} ```ts // Progressive performance alerts new TcpMonitor("mysql-performance", { @@ -218,6 +224,7 @@ new TcpMonitor("mysql-performance", { Maximum response time in milliseconds before the monitor is marked as failed. Usage: +{/* typecheck-wrap: TcpMonitor */} ```ts highlight={3} new TcpMonitor("fast-db", { name: "Fast DB Connection", @@ -230,6 +237,7 @@ new TcpMonitor("fast-db", { ``` Examples: +{/* typecheck-wrap: TcpMonitor */} ```ts // Low-latency database requirement new TcpMonitor("performance-db", { @@ -289,6 +297,7 @@ Learn more in our docs on [Assertions](/detect/assertions). Friendly name for your TCP monitor that will be displayed in the Checkly dashboard and used in notifications. Usage: +{/* typecheck-wrap: TcpMonitor */} ```ts highlight={2} new TcpMonitor('my-tcp-monitor', { name: 'Database Connection Monitor' @@ -315,6 +324,7 @@ Examples: +{/* typecheck-wrap: TcpMonitor */} ```ts // Database connectivity (high frequency) new TcpMonitor("critical-db", { @@ -327,6 +337,7 @@ new TcpMonitor("critical-db", { +{/* typecheck-wrap: TcpMonitor */} ```ts // Application service (standard frequency) new TcpMonitor("app-service", { @@ -339,6 +350,7 @@ new TcpMonitor("app-service", { +{/* typecheck-wrap: TcpMonitor */} ```ts // Background service (low frequency) new TcpMonitor("background-service", { @@ -358,9 +370,11 @@ new TcpMonitor("background-service", { Array of public location codes where the TCP monitor should run from. Multiple locations provide geographic coverage. Usage: +{/* typecheck-wrap: TcpMonitor */} ```ts highlight={2} new TcpMonitor('global-monitor', { - locations: ['us-east-1', 'eu-west-1', 'ap-southeast-1'] + locations: ['us-east-1', 'eu-west-1', 'ap-southeast-1'], + /* More options... */ }) ``` @@ -369,6 +383,7 @@ Examples: +{/* typecheck-wrap: TcpMonitor */} ```ts // Database replication monitoring new TcpMonitor("global-db", { @@ -389,6 +404,7 @@ new TcpMonitor("global-db", { +{/* typecheck-wrap: TcpMonitor */} ```ts // Regional service monitoring new TcpMonitor("eu-service", { @@ -412,13 +428,16 @@ new TcpMonitor("eu-service", { Whether the TCP monitor is enabled and will run according to its schedule. Usage: +{/* typecheck-wrap: TcpMonitor */} ```ts highlight={2} new TcpMonitor('my-monitor', { - activated: false // Disabled monitor + activated: false, // Disabled monitor + /* More options... */ }) ``` Examples: +{/* typecheck-wrap: TcpMonitor */} ```ts // Temporarily disable a monitor new TcpMonitor("maintenance-db", { @@ -438,6 +457,7 @@ new TcpMonitor("maintenance-db", { + {/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("postgres-check", { name: "PostgreSQL Connection", @@ -455,6 +475,7 @@ new TcpMonitor("maintenance-db", { + {/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("redis-check", { name: "Redis Connectivity", @@ -476,6 +497,7 @@ new TcpMonitor("maintenance-db", { + {/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("smtp-check", { name: "SMTP Server Check", @@ -496,6 +518,7 @@ new TcpMonitor("maintenance-db", { + {/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("ssh-check", { name: "SSH Connectivity", @@ -516,6 +539,7 @@ new TcpMonitor("maintenance-db", { + {/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("app-port-check", { name: "Custom Application Port", @@ -537,6 +561,7 @@ new TcpMonitor("maintenance-db", { + {/* typecheck-wrap: TcpMonitor */} ```ts new TcpMonitor("blocked-port-check", { name: "Verify Port is Blocked", diff --git a/constructs/telegram-alert-channel.mdx b/constructs/telegram-alert-channel.mdx index 39e17022..b4cb0190 100644 --- a/constructs/telegram-alert-channel.mdx +++ b/constructs/telegram-alert-channel.mdx @@ -77,6 +77,7 @@ The message sent to the chat when an alert is triggered. If this is not specifie We have [handlebar helpers and variables](/integrations/alerts/webhooks/#using-variables) available for building custom payloads. +{/* typecheck-wrap: TelegramAlertChannel */} ```ts highlight={5-16} new TelegramAlertChannel('my-telegramchannel-1', { name: 'My Telegram channel', diff --git a/constructs/traceroute-monitor.mdx b/constructs/traceroute-monitor.mdx index a9ea303b..3ef0c82a 100644 --- a/constructs/traceroute-monitor.mdx +++ b/constructs/traceroute-monitor.mdx @@ -98,6 +98,7 @@ Traceroute request configuration, including probe protocol, target host, and res **Usage:** +{/* typecheck-wrap: TracerouteMonitor */} ```ts new TracerouteMonitor('traceroute-monitor', { name: 'Network Path Monitor', @@ -133,6 +134,7 @@ Final-hop average RTT in milliseconds at which the monitor is marked as degraded **Usage:** +{/* typecheck-wrap: TracerouteMonitor */} ```ts highlight={3} new TracerouteMonitor("traceroute-latency-tiers", { name: "API Network Path", @@ -149,6 +151,7 @@ Final-hop average RTT in milliseconds at which the monitor is marked as failed. **Usage:** +{/* typecheck-wrap: TracerouteMonitor */} ```ts highlight={3} new TracerouteMonitor("traceroute-latency-tiers", { name: "API Network Path", @@ -211,6 +214,7 @@ Friendly name for your Traceroute Monitor that will be displayed in the Checkly **Usage:** +{/* typecheck-wrap: TracerouteMonitor */} ```ts highlight={2} new TracerouteMonitor("my-traceroute", { name: "API Gateway Network Path", @@ -224,6 +228,7 @@ How often the Traceroute Monitor should run. Use the `Frequency` enum to set the **Usage:** +{/* typecheck-wrap: TracerouteMonitor */} ```ts highlight={3} new TracerouteMonitor("my-traceroute", { name: "API Gateway Network Path", @@ -240,6 +245,7 @@ Array of [public location codes](/concepts/locations/#public-locations) where th **Usage:** +{/* typecheck-wrap: TracerouteMonitor */} ```ts highlight={3} new TracerouteMonitor("global-path-monitor", { name: "API Path from Multiple Regions", @@ -256,6 +262,7 @@ Whether the Traceroute Monitor is enabled and will run according to its schedule **Usage:** +{/* typecheck-wrap: TracerouteMonitor */} ```ts highlight={3} new TracerouteMonitor("my-traceroute", { name: "API Gateway Network Path", diff --git a/constructs/url-monitor.mdx b/constructs/url-monitor.mdx index 68b1c780..8a40c095 100644 --- a/constructs/url-monitor.mdx +++ b/constructs/url-monitor.mdx @@ -99,6 +99,7 @@ HTTP request configuration that defines the URL to monitor and how to handle the **Usage:** +{/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("url-monitor", { request: { @@ -107,7 +108,8 @@ new UrlMonitor("url-monitor", { assertions: [ UrlAssertionBuilder.statusCode().equals(200) ] - } + }, + /* More options... */ }) ``` @@ -126,6 +128,7 @@ new UrlMonitor("url-monitor", { +{/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor('website-check', { name: 'Website Availability', @@ -142,6 +145,7 @@ new UrlMonitor('website-check', { +{/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("api-health", { name: "API Health Check", @@ -157,6 +161,7 @@ new UrlMonitor("api-health", { +{/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("dev-endpoint", { name: "Development Environment", @@ -180,6 +185,7 @@ Response time threshold in milliseconds for marking the monitor as degraded (war **Usage:** +{/* typecheck-wrap: UrlMonitor */} ```ts highlight={4} // Progressive performance monitoring new UrlMonitor("performance-tiers", { @@ -201,6 +207,7 @@ Maximum response time in milliseconds before the monitor is marked as failed. **Usage:** +{/* typecheck-wrap: UrlMonitor */} ```ts highlight={3} new UrlMonitor("fast-site", { name: "Fast site", @@ -213,6 +220,7 @@ new UrlMonitor("fast-site", { **Examples:** +{/* typecheck-wrap: UrlMonitor */} ```ts // Fast website requirement new UrlMonitor("performance-critical", { @@ -268,6 +276,7 @@ Friendly name for your URL monitor that will be displayed in the Checkly dashboa **Usage:** +{/* typecheck-wrap: UrlMonitor */} ```ts highlight={2} new UrlMonitor("my-monitor", { name: "Website Uptime Monitor", @@ -282,6 +291,7 @@ How often the URL monitor should run. Use the `Frequency` enum to set the check **Usage:** +{/* typecheck-wrap: UrlMonitor */} ```ts highlight={2} new UrlMonitor("my-monitor", { frequency: Frequency.EVERY_1M, @@ -294,36 +304,42 @@ new UrlMonitor("my-monitor", { +{/* typecheck-wrap: UrlMonitor */} ```ts // Critical service monitoring new UrlMonitor("critical-service", { name: "Critical Service Uptime", frequency: Frequency.EVERY_30S, // Every 30 seconds - maxResponseTime: 2000 + maxResponseTime: 2000, + /* More options... */ }) ``` +{/* typecheck-wrap: UrlMonitor */} ```ts // Regular website monitoring new UrlMonitor("website-monitor", { name: "Website Availability", frequency: Frequency.EVERY_5M, // Every 5 minutes - maxResponseTime: 5000 + maxResponseTime: 5000, + /* More options... */ }) ``` +{/* typecheck-wrap: UrlMonitor */} ```ts // Background service monitoring new UrlMonitor("background-service", { name: "Background Service Health", frequency: Frequency.EVERY_30M, // Every 30 minutes - maxResponseTime: 10000 + maxResponseTime: 10000, + /* More options... */ }) ``` @@ -338,9 +354,11 @@ Array of public location codes where the URL monitor should run from. Multiple l **Usage:** +{/* typecheck-wrap: UrlMonitor */} ```ts highlight={2} new UrlMonitor("global-monitor", { - locations: ["us-east-1", "eu-west-1", "ap-southeast-1"] + locations: ["us-east-1", "eu-west-1", "ap-southeast-1"], + /* More options... */ }) ``` @@ -349,6 +367,7 @@ new UrlMonitor("global-monitor", { +{/* typecheck-wrap: UrlMonitor */} ```ts // Worldwide monitoring new UrlMonitor("global-website", { @@ -361,19 +380,22 @@ new UrlMonitor("global-website", { "ap-southeast-1", // Singapore "ap-northeast-1" // Tokyo ], - maxResponseTime: 5000 + maxResponseTime: 5000, + /* More options... */ }) ``` +{/* typecheck-wrap: UrlMonitor */} ```ts // European users focus new UrlMonitor("eu-service", { name: "European Service Monitor", frequency: Frequency.EVERY_1M, - locations: ["eu-west-1", "eu-central-1"] + locations: ["eu-west-1", "eu-central-1"], + /* More options... */ }) ``` @@ -388,14 +410,17 @@ Whether the URL monitor is enabled and will run according to its schedule. **Usage:** +{/* typecheck-wrap: UrlMonitor */} ```ts highlight={2} new UrlMonitor("my-monitor", { - activated: false // Disabled monitor + activated: false, // Disabled monitor + /* More options... */ }) ``` **Examples:** +{/* typecheck-wrap: UrlMonitor */} ```ts // Temporarily disable a monitor new UrlMonitor("maintenance-site", { @@ -414,6 +439,7 @@ new UrlMonitor("maintenance-site", { + {/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("website-availability", { name: "Main Website Availability", @@ -433,6 +459,7 @@ new UrlMonitor("maintenance-site", { + {/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("api-health-check", { name: "API Health Endpoint", @@ -453,6 +480,7 @@ new UrlMonitor("maintenance-site", { + {/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("cdn-performance", { name: "CDN Asset Performance", @@ -471,6 +499,7 @@ new UrlMonitor("maintenance-site", { + {/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("redirect-chain", { name: "Redirect Chain Monitor", @@ -490,6 +519,7 @@ new UrlMonitor("maintenance-site", { + {/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("ssl-certificate-check", { name: "SSL Certificate Validity", @@ -508,6 +538,7 @@ new UrlMonitor("maintenance-site", { ``` + {/* typecheck-wrap: UrlMonitor */} ```ts new UrlMonitor("maintenance-page", { name: "Maintenance Page Check", diff --git a/constructs/webhook-alert-channel.mdx b/constructs/webhook-alert-channel.mdx index b125c920..57a73e46 100644 --- a/constructs/webhook-alert-channel.mdx +++ b/constructs/webhook-alert-channel.mdx @@ -71,6 +71,7 @@ const webhookChannel = new WebhookAlertChannel('webhook-channel-1', { Target URL for the webhook request. +{/* typecheck-wrap: WebhookAlertChannel */} ```ts highlight={4} new WebhookAlertChannel('webhook-channel-1', { name: 'Pushover webhook', @@ -91,6 +92,7 @@ Friendly name for the webhook channel. The request body template, usually JSON. You can use [Handlebars-style template variables](/integrations/alerts/webhooks#using-variables) to further customize the template. +{/* typecheck-wrap: WebhookAlertChannel */} ```ts highlight={5-14} new WebhookAlertChannel('webhook-channel-1', { name: 'Pushover webhook', @@ -113,6 +115,7 @@ new WebhookAlertChannel('webhook-channel-1', { An array of `{ key, value }` objects to define HTTP headers. +{/* typecheck-wrap: WebhookAlertChannel */} ```ts highlight={5} new WebhookAlertChannel('webhook-channel-1', { name: 'Pushover webhook', @@ -126,6 +129,7 @@ new WebhookAlertChannel('webhook-channel-1', { An array of `{ key, value }` objects to define query parameters. +{/* typecheck-wrap: WebhookAlertChannel */} ```ts highlight={5} new WebhookAlertChannel('webhook-channel-1', { name: 'Pushover webhook', diff --git a/detect/synthetic-monitoring/playwright-checks/configuration.mdx b/detect/synthetic-monitoring/playwright-checks/configuration.mdx index 37e5d967..aa57a9b9 100644 --- a/detect/synthetic-monitoring/playwright-checks/configuration.mdx +++ b/detect/synthetic-monitoring/playwright-checks/configuration.mdx @@ -56,8 +56,11 @@ You can combine `pwTags` and `pwProjects` to generate your check suite, too. For example: -```typescript checkly.config.ts highlight={11, 20} +{/* typecheck-wrap */} +```typescript checkly.config.ts highlight={13, 22} export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', // ... checks: { playwrightConfigPath: './playwright.config.ts', diff --git a/detect/synthetic-monitoring/playwright-checks/overview.mdx b/detect/synthetic-monitoring/playwright-checks/overview.mdx index 23e2638d..941288e1 100644 --- a/detect/synthetic-monitoring/playwright-checks/overview.mdx +++ b/detect/synthetic-monitoring/playwright-checks/overview.mdx @@ -69,8 +69,11 @@ Control which tests run as monitors using: Configure test selection in your `checkly.config.ts` file: +{/* typecheck-wrap */} ```typescript checkly.config.ts export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightChecks: [ { diff --git a/detect/synthetic-monitoring/playwright-checks/quickstart.mdx b/detect/synthetic-monitoring/playwright-checks/quickstart.mdx index 0ef7698f..89cc8074 100644 --- a/detect/synthetic-monitoring/playwright-checks/quickstart.mdx +++ b/detect/synthetic-monitoring/playwright-checks/quickstart.mdx @@ -96,8 +96,11 @@ Each entry in the `playwrightChecks` array becomes a separate monitor. Use `pwPr This example creates two check suites — one for critical flows running every 5 minutes, and one for secondary features at a lower frequency: +{/* typecheck-wrap */} ```typescript checkly.config.ts export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', // ... config from above checks: { diff --git a/detect/synthetic-monitoring/playwright-checks/test-organization.mdx b/detect/synthetic-monitoring/playwright-checks/test-organization.mdx index d307af97..67ef3b0e 100644 --- a/detect/synthetic-monitoring/playwright-checks/test-organization.mdx +++ b/detect/synthetic-monitoring/playwright-checks/test-organization.mdx @@ -46,8 +46,11 @@ Remember: 99.9% uptime means about 1 minute and 26 seconds of downtime each day. The quickest way to reuse your existing Playwright end-to-end tests as Playwright Check Suites is to specify your Playwright config path and a single Playwright Check Suite in your `checkly.config.ts`. -```typescript highlight={3-11} +{/* typecheck-wrap */} +```typescript highlight={5-13} export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: "./playwright.config.ts", playwrightChecks: [ @@ -85,8 +88,11 @@ Select existing Playwright tests and run them in a Playwright Check Suite by rel Use the `pwProjects` option to choose Playwright projects defined in the `playwright.config.ts` by name. -```typescript checkly.config.ts highlight={10} +{/* typecheck-wrap */} +```typescript checkly.config.ts highlight={12} export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: "./playwright.config.ts", playwrightChecks: [ @@ -138,8 +144,11 @@ Using `pwProjects` creates a custom `testCommand` that includes the exact same ` Select existing Playwright tests and run them in a Playwright Check Suite by relying on [Playwright test annotations and tags](https://playwright.dev/docs/test-annotations#tag-tests). -```typescript checkly.config.ts highlight={9} +{/* typecheck-wrap */} +```typescript checkly.config.ts highlight={11} export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightChecks: [ { @@ -230,8 +239,11 @@ The Playwright test runner can always be configured at a global, project, or tes And configure different monitoring configuration for each Playwright project in your Playwright Check Suite. -```typescript checkly.config.ts highlight={8-12, 17-21} +{/* typecheck-wrap */} +```typescript checkly.config.ts highlight={10-14, 19-23} export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: "./playwright.config.ts", playwrightChecks: [ @@ -287,8 +299,11 @@ export default defineConfig({ And configure different monitoring configuration for each Playwright project in your Playwright Check Suite. -```typescript checkly.config.ts highlight={8-12, 17-21} +{/* typecheck-wrap */} +```typescript checkly.config.ts highlight={10-14, 19-23} export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: "./playwright.config.ts", playwrightChecks: [ @@ -344,8 +359,11 @@ export default defineConfig({ And configure different monitoring configuration for each Playwright project in your Playwright Check Suite. -```typescript checkly.config.ts highlight={8-14, 19-25} +{/* typecheck-wrap */} +```typescript checkly.config.ts highlight={10-16, 21-27} export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightConfigPath: "./playwright.config.ts", playwrightChecks: [ @@ -432,8 +450,11 @@ This Playwright setup will always run the `login-setup` project before running ` Reuse the `logged-in-tests` project in your Checkly configuration. -```typescript checkly.config.ts highlight={9} +{/* typecheck-wrap */} +```typescript checkly.config.ts highlight={11} export default defineConfig({ + projectName: 'My Project', + logicalId: 'my-project', checks: { playwrightChecks: [ { diff --git a/guides/communicate-availability.mdx b/guides/communicate-availability.mdx index 571c628d..6c21ac86 100644 --- a/guides/communicate-availability.mdx +++ b/guides/communicate-availability.mdx @@ -197,6 +197,7 @@ An automation rule connects tags to components. When a check with one of the rul Add the rules to the same file: +{/* typecheck-wrap: StatusPageV3AutomationRule */} ```ts checks/status-page.check.ts // When a check tagged status-storefront fails, the storefront is down. new StatusPageV3AutomationRule('storefront-outage', { diff --git a/integrations/iac/pulumi/best-practices.mdx b/integrations/iac/pulumi/best-practices.mdx index 3b0ba29b..c14d3fa4 100644 --- a/integrations/iac/pulumi/best-practices.mdx +++ b/integrations/iac/pulumi/best-practices.mdx @@ -460,6 +460,7 @@ Be mindful of Checkly's resource limits and pricing when creating large numbers ### Scalability +{/* typecheck-wrap */} ```javascript // Use loops for similar checks const endpoints = [ diff --git a/snippets/alert-channel-options-text.mdx b/snippets/alert-channel-options-text.mdx index 13edf097..21b4285f 100644 --- a/snippets/alert-channel-options-text.mdx +++ b/snippets/alert-channel-options-text.mdx @@ -15,6 +15,7 @@ Whether to send notifications when checks [become degraded](/communicate/alerts/ Whether to send notifications when a SSL/TLS certificate is about to expire. Default value is `false`. +{/* typecheck-wrap: EmailAlertChannel */} ```ts highlight={3} new EmailAlertChannel("email-channel-1", { address: "alerts@acme.com", @@ -29,6 +30,7 @@ new EmailAlertChannel("email-channel-1", { Number of days before the SSL/TLS certificate expiry date to send notifications. Only relevant when `sslExpiry` is enabled. Default value is `30`. +{/* typecheck-wrap: EmailAlertChannel */} ```ts highlight={4} new EmailAlertChannel("email-channel-1", { address: "alerts@acme.com", From bc498ef4920b3f6a480e0419e7aae96db2653e28 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 13:30:45 +0100 Subject: [PATCH 15/29] Make the snippet typecheck block PRs --- .github/workflows/static-docs-checks.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/static-docs-checks.yml b/.github/workflows/static-docs-checks.yml index bd3dc8e0..ddb0a838 100644 --- a/.github/workflows/static-docs-checks.yml +++ b/.github/workflows/static-docs-checks.yml @@ -78,13 +78,12 @@ jobs: - name: Test API navigation tooling run: npm run test:api-docs - # Typechecks MDX snippets that import from `checkly` against the - # installed CLI constructs, so examples don't drift from the CLI API. - # Errors show up as inline annotations on the PR. Report-only until the - # existing failures are fixed; then drop continue-on-error. + # Typechecks MDX snippets that import from `checkly`, and fragments + # marked with {/* typecheck-wrap */}, against the installed CLI + # constructs, so examples don't drift from the CLI API. Errors show up + # as inline annotations on the PR. - name: Typecheck checkly snippets if: steps.detect.outputs.docs_changed == 'true' || steps.detect.outputs.snippets_tooling_changed == 'true' - continue-on-error: true run: | npm run test:snippets npm run check:snippets From 16258102c4a612fb893c07108b90a7dfa2e83ab5 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 15:21:54 +0100 Subject: [PATCH 16/29] Typecheck JavaScript snippets that require checkly --- .github/scripts/typecheck-snippets.mjs | 2 +- .github/scripts/typecheck-snippets.test.mjs | 23 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index 338abf94..cc6b83a2 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -16,7 +16,7 @@ const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..'); const SKIP_MARKER = '{/* typecheck-skip */}'; const WRAP_MARKER = /^\{\/\* typecheck-wrap(?:: (\w+))? \*\/\}$/; const LANGS = { ts: 'ts', typescript: 'ts', js: 'js', javascript: 'js' }; -const CHECKLY_IMPORT = /from\s+['"]checkly(\/[\w-]+)?['"]/; +const CHECKLY_IMPORT = /(from\s+|require\(\s*)['"]checkly(\/[\w-]+)?['"]/; export function extractSnippets(mdx, file) { const lines = mdx.split('\n'); diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index 24c83fac..34dbae09 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -52,6 +52,29 @@ test('strips fence indentation and maps js fences to .js', () => { assert.equal(snippet.code, 'const { ApiCheck } = {}\nimport { Frequency } from "checkly/constructs"'); }); +test('extracts JavaScript blocks that require checkly', () => { + const mdx = [`${fence}js api.check.js`, `const { ApiCheck } = require('checkly/constructs')`, fence].join('\n'); + + const snippets = extractSnippets(mdx, 'page.mdx'); + + assert.equal(snippets.length, 1); + assert.equal(snippets[0].ext, 'js'); +}); + +test('reports construct API mismatches in CommonJS snippets', () => { + const errors = typecheckSnippets([{ ...snippet([ + `const { ApiCheck } = require('checkly/constructs')`, + `new ApiCheck('a', {`, + ` name: 'A',`, + ` request: { method: 'Foo', url: 'https://x.dev' },`, + `})`, + ].join('\n')), ext: 'js' }]); + + assert.equal(errors.length, 1); + assert.equal(errors[0].line, 13); + assert.match(errors[0].message, /Foo/); +}); + test('skips a block preceded by a typecheck-skip comment', () => { const mdx = [ '{/* typecheck-skip */}', From 83479bc7cb98d9a30dd91d07e5acfb2f6f90a420 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 15:34:32 +0100 Subject: [PATCH 17/29] Typecheck unmarked snippets that use checkly exports --- .github/scripts/typecheck-snippets.mjs | 24 +++++++++++---- .github/scripts/typecheck-snippets.test.mjs | 33 +++++++++++++++++++++ constructs/api-check.mdx | 4 +-- constructs/browser-check.mdx | 4 +-- constructs/tcp-monitor.mdx | 2 +- 5 files changed, 57 insertions(+), 10 deletions(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index cc6b83a2..c59c8f08 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -36,8 +36,10 @@ export function extractSnippets(mdx, file) { } if (/^\s*```\s*$/.test(text)) { const code = open.body.join('\n'); - if (open.ext && !open.skip && (open.wrap || CHECKLY_IMPORT.test(code))) { - snippets.push({ file, line: open.start + 1, ext: open.ext, code, ...(open.wrap && { wrap: open.wrap }) }); + const imports = CHECKLY_IMPORT.test(code); + const wrap = open.wrap ?? (!imports && CHECKLY_USE.test(code) ? true : undefined); + if (open.ext && !open.skip && (wrap || imports)) { + snippets.push({ file, line: open.start + 1, ext: open.ext, code, ...(wrap && { wrap }) }); } open = null; return; @@ -97,6 +99,17 @@ const autoImports = kind => [ ].join('; '); const AUTO_IMPORTS = { ts: autoImports('all'), js: autoImports('values') }; +// Blocks without a `checkly` import are checked as statement fragments when +// they use a checkly export (`new BrowserCheck(`, `Frequency.EVERY_5M`). +// Exports that are also globals, like `Request`, don't count. +const usableExports = [...constructExports.values, ...utilExports.values].filter(name => !(name in globalThis)).join('|'); +const CHECKLY_USE = new RegExp(`(? code.split(EQUIVALENT_TO)[0]; + // Fragments reference values defined elsewhere on the page (`statusPage`, // `group`). Checkly exports are auto-imported, so an unknown lowercase name is // page context; an unknown PascalCase name is a missing or misspelled construct. @@ -106,10 +119,11 @@ const isPageContextName = d => (d.code === 2304 || d.code === 18004) const isPropertyFragment = code => /^\w+\??:\s/.test(code.split('\n').map(l => l.trim()).find(l => l && !l.startsWith('//')) ?? ''); function source(snippet) { - if (!snippet.wrap) return { code: snippet.code, offset: 0 }; + const code = withoutEquivalent(snippet.code); + if (!snippet.wrap) return { code, offset: 0 }; const imports = AUTO_IMPORTS[snippet.ext]; - if (typeof snippet.wrap !== 'string' || !isPropertyFragment(snippet.code)) return { code: `${imports}\n${snippet.code}`, offset: 1 }; - return { code: `${imports}\nnew ${snippet.wrap}('snippet', {\n/* More options... */\n${snippet.code}\n})`, offset: 3 }; + if (typeof snippet.wrap !== 'string' || !isPropertyFragment(code)) return { code: `${imports}\n${code}`, offset: 1 }; + return { code: `${imports}\nnew ${snippet.wrap}('snippet', {\n/* More options... */\n${code}\n})`, offset: 3 }; } export function typecheckSnippets(snippets) { diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/scripts/typecheck-snippets.test.mjs index 34dbae09..fa02ded5 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/scripts/typecheck-snippets.test.mjs @@ -75,6 +75,39 @@ test('reports construct API mismatches in CommonJS snippets', () => { assert.match(errors[0].message, /Foo/); }); +test('extracts unmarked blocks that use a checkly export as statement fragments', () => { + const mdx = [ + `${fence}ts Login Flow`, + `new BrowserCheck('login', { name: 'Login' })`, + fence, + '', + `${fence}ts`, + `UrlAssertionBuilder.statusCode().equals(200)`, + fence, + '', + `${fence}js`, + `const res = await fetch(new Request('https://x.dev'))`, + fence, + '', + `${fence}ts`, + `const frequency = 'often'`, + fence, + ].join('\n'); + + const snippets = extractSnippets(mdx, 'page.mdx'); + + assert.deepEqual(snippets.map(s => [s.line, s.wrap]), [[2, true], [6, true]]); +}); + +test('ignores the object literal after an "Equivalent to" comment', () => { + const errors = typecheckSnippets([ + fragment(`UrlAssertionBuilder.statusCode().equals(200)\n// Equivalent to:\n{ source: 'STATUS_CODE', comparison: 'EQUALS', target: '200' }`, true), + fragment(`UrlAssertionBuilder.statusCode().isFast()\n// Equivalent to:\n{ source: 'STATUS_CODE' }`, true, 30), + ]); + + assert.deepEqual(errors.map(e => e.line), [30]); +}); + test('skips a block preceded by a typecheck-skip comment', () => { const mdx = [ '{/* typecheck-skip */}', diff --git a/constructs/api-check.mdx b/constructs/api-check.mdx index 62be0a29..2008b670 100644 --- a/constructs/api-check.mdx +++ b/constructs/api-check.mdx @@ -466,7 +466,7 @@ AssertionBuilder.statusCode().equals(200) - Asserting a part of a JSON response body using a JSON path expression ```ts -AssertionBuilder.jsonBody('$.data').greaterThan(2000), +AssertionBuilder.jsonBody('$.data').greaterThan(2000) // Equivalent to: { source: 'JSON_BODY', property: '$.data', comparison: 'GREATER_THAN', target: '2000' } ``` @@ -474,7 +474,7 @@ AssertionBuilder.jsonBody('$.data').greaterThan(2000), - Asserting the value of a part of an HTTP response header. Note that you can pass in a regex as the second argument ```ts -AssertionBuilder.headers('strict-transport-security', 'max-age=(\\d+)').greaterThan(10000), +AssertionBuilder.headers('strict-transport-security', 'max-age=(\\d+)').greaterThan(10000) // Equivalent to: { source: 'HEADERS', regex: 'max-age=(\d+)', property: 'strict-transport-security', comparison: 'GREATER_THAN', target: '10000' } ``` diff --git a/constructs/browser-check.mdx b/constructs/browser-check.mdx index ea835811..f437c217 100644 --- a/constructs/browser-check.mdx +++ b/constructs/browser-check.mdx @@ -488,8 +488,8 @@ import { expect, test } from "@playwright/test" test("user can login successfully", async ({ page }) => { await page.goto("https://app.example.com/login") - await page.getByLabel('email', { name: /email/i }).fill(process.env.TEST_USERNAME) - await page.getByLabel('password', { name: /password/i }).fill(process.env.TEST_PASSWORD) + await page.getByLabel(/email/i).fill(process.env.TEST_USERNAME) + await page.getByLabel(/password/i).fill(process.env.TEST_PASSWORD) await page.getByRole('button', { name: /login/i }).click() await expect(page).toHaveURL(/dashboard/) diff --git a/constructs/tcp-monitor.mdx b/constructs/tcp-monitor.mdx index 76794ed5..7ea51d8d 100644 --- a/constructs/tcp-monitor.mdx +++ b/constructs/tcp-monitor.mdx @@ -276,7 +276,7 @@ Here are some examples: - Assert the total response time of the TCP request ```ts -TcpAssertionBuilder.responseTime().lessThan(1000), +TcpAssertionBuilder.responseTime().lessThan(1000) // Equivalent to: { source: 'RESPONSE_TIME', comparison: 'LESS_THAN', target: '1000' } ``` From 692bd8c6ca2de4c886240ff1b6a47952e4d79f81 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 15:34:47 +0100 Subject: [PATCH 18/29] Describe auto-detected fragments in the snippet checker header --- .github/scripts/typecheck-snippets.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/scripts/typecheck-snippets.mjs index c59c8f08..fdfce8cd 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/scripts/typecheck-snippets.mjs @@ -1,9 +1,10 @@ // Typechecks MDX code snippets that import from `checkly` against the // installed Checkly CLI constructs, so docs examples don't drift from the CLI. // -// Complete snippets (ones with a `checkly` import) are checked. Fragments are -// checked when `{/* typecheck-wrap: ApiCheck */}` (or `{/* typecheck-wrap */}` -// for statements) is on the line before their fence. Snippets with a `/* More options... */` comment may omit required +// Complete snippets (ones with a `checkly` import) are checked, and so are +// fragments that use a checkly export. Property fragments like `request: {...}` +// are checked when `{/* typecheck-wrap: ApiCheck */}` (or `{/* typecheck-wrap */}` +// for other statements) is on the line before their fence. Snippets with a `/* More options... */` comment may omit required // props. Opt a block out with `{/* typecheck-skip */}` on the line before it. // // Usage: node .github/scripts/typecheck-snippets.mjs [root] From bc4e577d80dff051f198069a292a94f994024860 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 15:39:13 +0100 Subject: [PATCH 19/29] Add @checkly/playwright-helpers so snippets using it typecheck --- package-lock.json | 25 +++++++++++++++++++++++++ package.json | 1 + 2 files changed, 26 insertions(+) diff --git a/package-lock.json b/package-lock.json index 60b6aa81..ce1af9ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { + "@checkly/playwright-helpers": "1.0.4", "@mintlify/link-rot": "3.0.803", "@playwright/test": "^1.40.0", "@types/node": "22.20.5", @@ -171,6 +172,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@checkly/playwright-helpers": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@checkly/playwright-helpers/-/playwright-helpers-1.0.4.tgz", + "integrity": "sha512-toZb8yUdlL76093t8tBBQy+udbofrPcwIvDvCaEaAxlG0j/IWfcaQibMmN04EufdndGduVyt1ZDmfjbzyw74/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "typescript": "5.3.3" + } + }, + "node_modules/@checkly/playwright-helpers/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@emnapi/runtime": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", diff --git a/package.json b/package.json index 88042eda..108a7875 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "guides:screenshots": "tsx scripts/guides/screenshots/capture.ts" }, "devDependencies": { + "@checkly/playwright-helpers": "1.0.4", "@mintlify/link-rot": "3.0.803", "@playwright/test": "^1.40.0", "@types/node": "22.20.5", From b5c540569b48cddfd0fa55e5adc25bf21e301c48 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 15:59:14 +0100 Subject: [PATCH 20/29] Typecheck snippets against the latest checkly release in its own package --- .github/snippet-typecheck/.npmrc | 2 + .github/snippet-typecheck/package.json | 17 ++++++++ .../typecheck-snippets.mjs | 21 ++++++---- .../typecheck-snippets.test.mjs | 13 +++++- .github/workflows/static-docs-checks.yml | 24 ++++++----- package-lock.json | 40 ++++--------------- package.json | 4 -- 7 files changed, 65 insertions(+), 56 deletions(-) create mode 100644 .github/snippet-typecheck/.npmrc create mode 100644 .github/snippet-typecheck/package.json rename .github/{scripts => snippet-typecheck}/typecheck-snippets.mjs (91%) rename .github/{scripts => snippet-typecheck}/typecheck-snippets.test.mjs (94%) diff --git a/.github/snippet-typecheck/.npmrc b/.github/snippet-typecheck/.npmrc new file mode 100644 index 00000000..d986c66e --- /dev/null +++ b/.github/snippet-typecheck/.npmrc @@ -0,0 +1,2 @@ +# Always typecheck against the latest releases, so no lockfile. +package-lock=false diff --git a/.github/snippet-typecheck/package.json b/.github/snippet-typecheck/package.json new file mode 100644 index 00000000..deb1c382 --- /dev/null +++ b/.github/snippet-typecheck/package.json @@ -0,0 +1,17 @@ +{ + "name": "snippet-typecheck", + "private": true, + "description": "Typechecks the docs' code snippets against the latest Checkly CLI. Install with `npm install` in this folder.", + "type": "module", + "scripts": { + "check": "node typecheck-snippets.mjs ../..", + "test": "node --test typecheck-snippets.test.mjs" + }, + "dependencies": { + "@checkly/playwright-helpers": "latest", + "@playwright/test": "latest", + "@types/node": "latest", + "checkly": "latest", + "typescript": "^6.0.0" + } +} diff --git a/.github/scripts/typecheck-snippets.mjs b/.github/snippet-typecheck/typecheck-snippets.mjs similarity index 91% rename from .github/scripts/typecheck-snippets.mjs rename to .github/snippet-typecheck/typecheck-snippets.mjs index fdfce8cd..eb4a4241 100644 --- a/.github/scripts/typecheck-snippets.mjs +++ b/.github/snippet-typecheck/typecheck-snippets.mjs @@ -7,13 +7,15 @@ // for other statements) is on the line before their fence. Snippets with a `/* More options... */` comment may omit required // props. Opt a block out with `{/* typecheck-skip */}` on the line before it. // -// Usage: node .github/scripts/typecheck-snippets.mjs [root] +// Usage: npm install && npm run check (in .github/snippet-typecheck) import { readdirSync, readFileSync, existsSync } from 'node:fs'; import { dirname, join, relative, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; import ts from 'typescript'; -const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..'); +// Modules resolve from this folder's node_modules, which installs the latest +// checkly release independently of the docs project's own dependencies. +const toolRoot = dirname(fileURLToPath(import.meta.url)); const SKIP_MARKER = '{/* typecheck-skip */}'; const WRAP_MARKER = /^\{\/\* typecheck-wrap(?:: (\w+))? \*\/\}$/; const LANGS = { ts: 'ts', typescript: 'ts', js: 'js', javascript: 'js' }; @@ -60,6 +62,9 @@ const compilerOptions = { skipLibCheck: true, noEmit: true, types: ['node'], + // Snippets read `process.env.X` without null checks, as checks usually do. + // TypeScript 6 turns strict on by default, so keep it off explicitly. + strict: false, }; // Multi-file examples import siblings like `./group.check`. Those can't @@ -76,7 +81,7 @@ const isOnlyMissingProps = d => MISSING_PROPS.has(d.code) || (d.code === 2345 && // Exports of a module read from its type declarations, split into values and // types, because JavaScript files can't import types. function moduleExports(specifiers) { - const files = specifiers.map(s => ts.resolveModuleName(s, join(repoRoot, 'index.ts'), compilerOptions, ts.sys).resolvedModule.resolvedFileName); + const files = specifiers.map(s => ts.resolveModuleName(s, join(toolRoot, 'index.ts'), compilerOptions, ts.sys).resolvedModule.resolvedFileName); const program = ts.createProgram(files, compilerOptions); const checker = program.getTypeChecker(); return files.map(f => { @@ -128,7 +133,7 @@ function source(snippet) { } export function typecheckSnippets(snippets) { - const virtual = new Map(snippets.map((s, i) => [join(repoRoot, '.snippets', `${i}.${s.ext}`).split(sep).join('/'), { ...s, ...source(s) }])); + const virtual = new Map(snippets.map((s, i) => [join(toolRoot, '.snippets', `${i}.${s.ext}`).split(sep).join('/'), { ...s, ...source(s) }])); const host = ts.createCompilerHost(compilerOptions); const { getSourceFile, fileExists, readFile } = host; host.fileExists = f => virtual.has(f) || fileExists(f); @@ -162,8 +167,8 @@ export function typecheckSnippets(snippets) { return errors; } -function mdxFiles(root) { - const ignoredDirs = ['node_modules', 'samples', '.git']; +export function mdxFiles(root) { + const ignoredDirs = ['samples', '.git']; const mintignore = join(root, '.mintignore'); if (existsSync(mintignore)) { for (const entry of readFileSync(mintignore, 'utf8').split('\n')) { @@ -177,7 +182,7 @@ function mdxFiles(root) { for (const entry of readdirSync(dir, { withFileTypes: true })) { const path = join(dir, entry.name); if (entry.isDirectory()) { - if (!ignoredDirs.includes(relative(root, path).split(sep).join('/'))) walk(path); + if (entry.name !== 'node_modules' && !ignoredDirs.includes(relative(root, path).split(sep).join('/'))) walk(path); } else if (entry.name.endsWith('.mdx')) { files.push(path); } @@ -200,7 +205,7 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) { } } - const checklyVersion = JSON.parse(readFileSync(join(repoRoot, 'node_modules/checkly/package.json'), 'utf8')).version; + const checklyVersion = JSON.parse(readFileSync(join(toolRoot, 'node_modules/checkly/package.json'), 'utf8')).version; console.log(`Typechecked ${snippets.length} snippets against checkly@${checklyVersion}: ${errors.length} error(s).`); if (errors.length > 0) process.exitCode = 1; } diff --git a/.github/scripts/typecheck-snippets.test.mjs b/.github/snippet-typecheck/typecheck-snippets.test.mjs similarity index 94% rename from .github/scripts/typecheck-snippets.test.mjs rename to .github/snippet-typecheck/typecheck-snippets.test.mjs index fa02ded5..53ca0af7 100644 --- a/.github/scripts/typecheck-snippets.test.mjs +++ b/.github/snippet-typecheck/typecheck-snippets.test.mjs @@ -1,6 +1,9 @@ import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; import test from 'node:test'; -import { extractSnippets, typecheckSnippets } from './typecheck-snippets.mjs'; +import { extractSnippets, mdxFiles, typecheckSnippets } from './typecheck-snippets.mjs'; const fence = '```'; @@ -140,6 +143,14 @@ test('extracts fragments marked with typecheck-wrap even without a checkly impor assert.equal(fragment.line, 3); }); +test('finds MDX files outside node_modules folders at any depth', () => { + const root = mkdtempSync(join(tmpdir(), 'snippets-')); + for (const dir of ['docs', 'node_modules/pkg', 'tools/node_modules/pkg']) mkdirSync(join(root, dir), { recursive: true }); + for (const file of ['docs/page.mdx', 'node_modules/pkg/readme.mdx', 'tools/node_modules/pkg/readme.mdx']) writeFileSync(join(root, file), ''); + + assert.deepEqual(mdxFiles(root).map(f => f.slice(root.length + 1)), ['docs/page.mdx']); +}); + function snippet(code, line = 10) { return { file: 'page.mdx', line, ext: 'ts', code }; } diff --git a/.github/workflows/static-docs-checks.yml b/.github/workflows/static-docs-checks.yml index ddb0a838..eed013bb 100644 --- a/.github/workflows/static-docs-checks.yml +++ b/.github/workflows/static-docs-checks.yml @@ -45,9 +45,9 @@ jobs: echo "openapi_changed=false" >> "$GITHUB_OUTPUT" fi - # A checkly CLI bump or a change to the snippet checker re-runs the - # snippet typecheck even when no docs changed. - if echo "$CHANGED" | grep -qE '^(package(-lock)?\.json|\.github/scripts/typecheck-snippets(\.test)?\.mjs)$'; then + # A change to the snippet checker re-runs the snippet typecheck even + # when no docs changed. + if echo "$CHANGED" | grep -q '^\.github/snippet-typecheck/'; then echo "snippets_tooling_changed=true" >> "$GITHUB_OUTPUT" else echo "snippets_tooling_changed=false" >> "$GITHUB_OUTPUT" @@ -68,7 +68,7 @@ jobs: cache: 'npm' - name: Install dependencies - if: steps.detect.outputs.openapi_changed == 'true' || steps.detect.outputs.docs_changed == 'true' || steps.detect.outputs.snippets_tooling_changed == 'true' + if: steps.detect.outputs.openapi_changed == 'true' || steps.detect.outputs.docs_changed == 'true' run: npm ci - name: Validate OpenAPI spec @@ -78,15 +78,19 @@ jobs: - name: Test API navigation tooling run: npm run test:api-docs - # Typechecks MDX snippets that import from `checkly`, and fragments - # marked with {/* typecheck-wrap */}, against the installed CLI - # constructs, so examples don't drift from the CLI API. Errors show up - # as inline annotations on the PR. + # Typechecks MDX snippets that use `checkly`, and fragments marked with + # {/* typecheck-wrap */}, against the latest CLI constructs, so examples + # don't drift from the CLI API. The checker has its own package.json + # without a lockfile, so every run installs the latest checkly release + # rather than the docs project's pinned version. Errors show up as + # inline annotations on the PR. - name: Typecheck checkly snippets if: steps.detect.outputs.docs_changed == 'true' || steps.detect.outputs.snippets_tooling_changed == 'true' + working-directory: .github/snippet-typecheck run: | - npm run test:snippets - npm run check:snippets + npm install --no-audit --no-fund + npm test + npm run check - name: Check API group badges match the schema run: npm run sync:api-group-tags -- --check diff --git a/package-lock.json b/package-lock.json index 471909b9..459c38c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,8 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@checkly/playwright-helpers": "1.0.4", "@mintlify/link-rot": "3.0.803", "@playwright/test": "^1.40.0", - "@types/node": "22.20.5", "checkly": "10.0.0", "mint": "4.2.1031", "tsx": "^4.23.15", @@ -284,30 +282,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@checkly/playwright-helpers": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@checkly/playwright-helpers/-/playwright-helpers-1.0.4.tgz", - "integrity": "sha512-toZb8yUdlL76093t8tBBQy+udbofrPcwIvDvCaEaAxlG0j/IWfcaQibMmN04EufdndGduVyt1ZDmfjbzyw74/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "typescript": "5.3.3" - } - }, - "node_modules/@checkly/playwright-helpers/node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@emnapi/runtime": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", @@ -8188,13 +8162,13 @@ } }, "node_modules/@types/node": { - "version": "22.20.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.5.tgz", - "integrity": "sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==", + "version": "24.2.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz", + "integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.10.0" } }, "node_modules/@types/react": { @@ -20479,9 +20453,9 @@ } }, "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 4e872f6d..e813c857 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,6 @@ "dev": "mint dev", "test:api-docs": "node --test .github/scripts/api-navigation.test.mjs", "check:links": "node .github/scripts/check-broken-links.mjs", - "check:snippets": "node .github/scripts/typecheck-snippets.mjs", - "test:snippets": "node --test .github/scripts/typecheck-snippets.test.mjs", "sync:api-group-tags": "node .github/scripts/sync-api-group-tags.mjs", "deploy": "checkly deploy", "test": "checkly test", @@ -19,10 +17,8 @@ "guides:screenshots": "tsx scripts/guides/screenshots/capture.ts" }, "devDependencies": { - "@checkly/playwright-helpers": "1.0.4", "@mintlify/link-rot": "3.0.803", "@playwright/test": "^1.40.0", - "@types/node": "22.20.5", "checkly": "10.0.0", "mint": "4.2.1031", "tsx": "^4.23.15", From 9fef6cb8daeea42da797269e5862da4d0e18c8e9 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 16:06:31 +0100 Subject: [PATCH 21/29] Regenerate lockfile with npm 10 so npm ci works in CI --- package-lock.json | 200 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 176 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 459c38c5..7897e660 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2650,6 +2650,71 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/@mintlify/cli/node_modules/@puppeteer/browsers": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.7.1.tgz", + "integrity": "sha512-MK7rtm8JjaxPN7Mf1JdZIZKPD2Z+W7osvrC1vjpvfOX1K0awDIHYbNi89f7eotp7eMUn2shWnt03HwVbriXtKQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.0", + "tar-fs": "^3.0.8", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@mintlify/cli/node_modules/@puppeteer/browsers/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@mintlify/cli/node_modules/@puppeteer/browsers/node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@mintlify/cli/node_modules/acorn": { "version": "8.11.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", @@ -2757,6 +2822,34 @@ "node": ">=18" } }, + "node_modules/@mintlify/cli/node_modules/chromium-bidi": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-2.1.2.tgz", + "integrity": "sha512-vtRWBK2uImo5/W2oG6/cDkkHSm+2t6VHgnj+Rcwhb0pP74OoUb4GipyRX/T/y39gYQPhioP0DPShn+A7P6CHNw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/@mintlify/cli/node_modules/chromium-bidi/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/@mintlify/cli/node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -2794,6 +2887,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@mintlify/cli/node_modules/devtools-protocol": { + "version": "0.0.1402036", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1402036.tgz", + "integrity": "sha512-JwAYQgEvm3yD45CHB+RmF5kMbWtXBaOGwuxa87sZogHcLCv8c/IqnThaoQ1y60d7pXWjSKWQphPEc+1rAScVdg==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "peer": true + }, "node_modules/@mintlify/cli/node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -3121,6 +3223,71 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/@mintlify/cli/node_modules/puppeteer": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.3.1.tgz", + "integrity": "sha512-k0OJ7itRwkr06owp0CP3f/PsRD7Pdw4DjoCUZvjGr+aNgS1z6n/61VajIp0uBjl+V5XAQO1v/3k9bzeZLWs9OQ==", + "deprecated": "< 24.15.0 is no longer supported", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "@puppeteer/browsers": "2.7.1", + "chromium-bidi": "2.1.2", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1402036", + "puppeteer-core": "24.3.1", + "typed-query-selector": "^2.12.0" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@mintlify/cli/node_modules/puppeteer-core": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.3.1.tgz", + "integrity": "sha512-585ccfcTav4KmlSmYbwwOSeC8VdutQHn2Fuk0id/y/9OoeO7Gg5PK1aUGdZjEmos0TAq+pCpChqFurFbpNd3wA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "@puppeteer/browsers": "2.7.1", + "chromium-bidi": "2.1.2", + "debug": "^4.4.0", + "devtools-protocol": "0.0.1402036", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@mintlify/cli/node_modules/puppeteer-core/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/@mintlify/cli/node_modules/qs": { "version": "6.14.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", @@ -6621,9 +6788,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6641,9 +6805,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6661,9 +6822,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6681,9 +6839,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6701,9 +6856,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6721,9 +6873,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6741,9 +6890,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6761,9 +6907,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -20378,6 +20521,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typed-query-selector": { + "version": "2.12.3", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.3.tgz", + "integrity": "sha512-/dtuMZyutHLlrxWhhC1uib00ELUr2dZ8C9B8YzZYsJmeE3V56OxRblrSM2UaF142pcMtak7ehZ6+poWGeehNIg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", From 8bc495fce1d4b2d070fad835e56ef19de3d1d95f Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 16:11:05 +0100 Subject: [PATCH 22/29] Add root npm scripts for the snippet typecheck --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index e813c857..a82e6bae 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "dev": "mint dev", "test:api-docs": "node --test .github/scripts/api-navigation.test.mjs", "check:links": "node .github/scripts/check-broken-links.mjs", + "check:snippets": "cd .github/snippet-typecheck && npm install --no-audit --no-fund --silent && npm run check --silent", + "test:snippets": "cd .github/snippet-typecheck && npm install --no-audit --no-fund --silent && npm test --silent", "sync:api-group-tags": "node .github/scripts/sync-api-group-tags.mjs", "deploy": "checkly deploy", "test": "checkly test", From 171394a841e07b6869d689292d87b2dc6cc5167b Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 16:12:38 +0100 Subject: [PATCH 23/29] Suggest a More options comment on missing-props snippet errors --- .github/snippet-typecheck/typecheck-snippets.mjs | 3 ++- .github/snippet-typecheck/typecheck-snippets.test.mjs | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/snippet-typecheck/typecheck-snippets.mjs b/.github/snippet-typecheck/typecheck-snippets.mjs index eb4a4241..a4fbf243 100644 --- a/.github/snippet-typecheck/typecheck-snippets.mjs +++ b/.github/snippet-typecheck/typecheck-snippets.mjs @@ -75,6 +75,7 @@ const isUnresolvedRelativeImport = d => d.code === 2307 && /module '\.\.?\//.tes // a missing required prop is intended; wrong or unknown props still fail. const PARTIAL_MARKER = /\/\*\s*More options/i; const MISSING_PROPS = new Set([2739, 2740, 2741]); +const MORE_OPTIONS_HINT = 'Shortened on purpose? Add `/* More options... */` where the props are left out.'; const isOnlyMissingProps = d => MISSING_PROPS.has(d.code) || (d.code === 2345 && typeof d.messageText === 'object' && d.messageText.next?.length > 0 && d.messageText.next.every(n => MISSING_PROPS.has(n.code))); @@ -159,7 +160,7 @@ export function typecheckSnippets(snippets) { file: snippet.file, line: snippet.line + Math.max(0, line - snippet.offset), column: line < snippet.offset ? 1 : character + 1, - message: `TS${d.code}: ${ts.flattenDiagnosticMessageText(d.messageText, '\n')}`, + message: `TS${d.code}: ${ts.flattenDiagnosticMessageText(d.messageText, '\n')}${isOnlyMissingProps(d) ? `\n${MORE_OPTIONS_HINT}` : ''}`, }); } } diff --git a/.github/snippet-typecheck/typecheck-snippets.test.mjs b/.github/snippet-typecheck/typecheck-snippets.test.mjs index 53ca0af7..a3977327 100644 --- a/.github/snippet-typecheck/typecheck-snippets.test.mjs +++ b/.github/snippet-typecheck/typecheck-snippets.test.mjs @@ -233,6 +233,17 @@ test('reports missing required props in complete snippets', () => { assert.match(errors[0].message, /'code' is missing/); }); +test('suggests a "More options" comment for missing props, and only for those', () => { + const errors = typecheckSnippets([ + snippet(`import { BrowserCheck } from 'checkly/constructs'\nnew BrowserCheck('a', { name: 'A' })`), + snippet(`import { BrowserCheck } from 'checkly/constructs'\nnew BrowserCheck('a', { name: 'A', code: { content: '' }, doesNotExist: true })`, 30), + ]); + + assert.equal(errors.length, 2); + assert.match(errors[0].message, /'code' is missing[\s\S]*Shortened on purpose\? Add `\/\* More options\.\.\. \*\/`/); + assert.doesNotMatch(errors[1].message, /More options/); +}); + function fragment(code, wrap = 'ApiCheck', line = 10) { return { file: 'page.mdx', line, ext: 'ts', code, wrap }; } From 0f45a6fe754fdd401594bf0f453cc56b6fb5a897 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Wed, 28 Oct 2026 16:17:56 +0100 Subject: [PATCH 24/29] Tidy snippet examples and trailing whitespace --- cli/checkly-runtimes.mdx | 1 - cli/importing.mdx | 1 - constructs/overview.mdx | 6 +++--- constructs/retry-strategy.mdx | 2 +- constructs/sms-alert-channel.mdx | 4 ++-- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cli/checkly-runtimes.mdx b/cli/checkly-runtimes.mdx index 971ef585..02afcd74 100644 --- a/cli/checkly-runtimes.mdx +++ b/cli/checkly-runtimes.mdx @@ -82,7 +82,6 @@ import { ApiCheck } from 'checkly/constructs' new ApiCheck('books-api-check-2', { name: 'Books API', runtimeId: '2025.04', - request: { method: 'GET', url: 'https://danube-web.shop/api/books' }, /* More options... */ }) ``` diff --git a/cli/importing.mdx b/cli/importing.mdx index eb62394c..25952715 100644 --- a/cli/importing.mdx +++ b/cli/importing.mdx @@ -73,7 +73,6 @@ new BrowserCheck('check-landing-page-3eNrQgOb', { code: { entrypoint: './check-landing-page.spec.ts', }, - /* More options... */ alertChannels: [ // Note the usage of the imported alert channel here emailAlert1, diff --git a/constructs/overview.mdx b/constructs/overview.mdx index 0137d551..b7f907da 100644 --- a/constructs/overview.mdx +++ b/constructs/overview.mdx @@ -5,12 +5,12 @@ sidebarTitle: 'Overview' canonical: 'https://www.checklyhq.com/docs/constructs/overview/' --- -import JsTsNote from '/snippets/js-ts-note.mdx'; import ChecklyConfigCodeBlock from '/snippets/checkly-config-example-code-block.mdx'; +import JsTsNote from '/snippets/js-ts-note.mdx'; Every resource you create using the [Checkly CLI](/cli/overview/) is represented by a "construct": it's a class you import from `checkly/constructs`, -for instance an `ApiCheck` or `EmailAlertChannel`. A construct is the "as-code" representation of the eventual resource +for instance an `ApiCheck` or `EmailAlertChannel`. A construct is the "as-code" representation of the eventual resource created / deleted / updated on the Checkly cloud once you run `npx checkly deploy`. @@ -161,4 +161,4 @@ All resources you can create and manage using the Checkly CLI are derived from " [TypeScript classes](https://github.com/checkly/checkly-cli/tree/main/packages/cli/src/constructs). You can use standard JS/TS programming to use these constructs to create the monitoring setup of your -choice. Loops, variables, if-statements, file imports, extensions etc. [Here are some examples.](/constructs/dynamic-monitor-creation) \ No newline at end of file +choice. Loops, variables, if-statements, file imports, extensions etc. [Here are some examples.](/constructs/dynamic-monitor-creation) diff --git a/constructs/retry-strategy.mdx b/constructs/retry-strategy.mdx index fdd52221..7dc773eb 100644 --- a/constructs/retry-strategy.mdx +++ b/constructs/retry-strategy.mdx @@ -350,7 +350,7 @@ When `sameRegion: false`, retries are attempted from different regions to help d -Apply the retry strategy only when the failure cause matches the specified condition. +Apply the retry strategy only when the failure cause matches the specified condition. **Usage:** diff --git a/constructs/sms-alert-channel.mdx b/constructs/sms-alert-channel.mdx index a4f2caf9..653e59e3 100644 --- a/constructs/sms-alert-channel.mdx +++ b/constructs/sms-alert-channel.mdx @@ -49,9 +49,9 @@ const smsChannel = new SmsAlertChannel('sms-channel-1', { ### SMS Alert Channel Options -Phone number to send SMS notifications to. +Phone number to send SMS notifications to. -Each `SmsAlertChannel` supports only one phone number. Phone numbers need to be in [E.164 format](https://www.twilio.com/docs/glossary/what-e164). +Each `SmsAlertChannel` supports only one phone number. Phone numbers need to be in [E.164 format](https://www.twilio.com/docs/glossary/what-e164). We only support phone numbers from certain [countries and regions](/integrations/alerts/sms#supported-countries-and-regions). From 7e90d67885c36f3bcbef4cda92a9cbf857253a7c Mon Sep 17 00:00:00 2001 From: stefan judis Date: Fri, 30 Oct 2026 12:17:58 +0100 Subject: [PATCH 25/29] Pass the JS config to defineConfig directly so it typechecks --- cli/installation.mdx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cli/installation.mdx b/cli/installation.mdx index 2347b89c..c85474d9 100644 --- a/cli/installation.mdx +++ b/cli/installation.mdx @@ -62,7 +62,7 @@ Create a minimal `checkly.config.ts` (or `checkly.config.js`) at the root of you const { defineConfig } = require('checkly') const { Frequency } = require('checkly/constructs') - const config = { + module.exports = defineConfig({ projectName: 'Website Monitoring', logicalId: 'website-monitoring-1', repoUrl: 'https://github.com/acme/website', @@ -83,9 +83,7 @@ Create a minimal `checkly.config.ts` (or `checkly.config.js`) at the root of you cli: { runLocation: 'eu-central-1', } - } - - module.exports = defineConfig(config); + }) ``` From 0676313787b18364f884f74e479634eac27a87cc Mon Sep 17 00:00:00 2001 From: stefan judis Date: Fri, 30 Oct 2026 12:18:32 +0100 Subject: [PATCH 26/29] Ignore Facebook requests in the console errors check --- __checks__/no-console-errors.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/__checks__/no-console-errors.spec.ts b/__checks__/no-console-errors.spec.ts index 6c15b6d9..4e71a9f5 100644 --- a/__checks__/no-console-errors.spec.ts +++ b/__checks__/no-console-errors.spec.ts @@ -9,6 +9,7 @@ const paths = ['/', '/api-reference', '/cli'] const ignoredUrls = [ /\/_vercel\/insights\//, /cdn\.segment\.com/, + /facebook\.(com|net)/, /px\.ads\.linkedin\.com/, /unifyintent\.com/, ] From b0fe384e433a67413b000c1ba2d0732d31d571fb Mon Sep 17 00:00:00 2001 From: stefan judis Date: Fri, 30 Oct 2026 12:23:07 +0100 Subject: [PATCH 27/29] Refresh snippet checker deps to latest and disable their install scripts --- .github/snippet-typecheck/.npmrc | 2 ++ .github/snippet-typecheck/package.json | 2 +- .github/snippet-typecheck/typecheck-snippets.mjs | 10 +++++----- package.json | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/snippet-typecheck/.npmrc b/.github/snippet-typecheck/.npmrc index d986c66e..756225e5 100644 --- a/.github/snippet-typecheck/.npmrc +++ b/.github/snippet-typecheck/.npmrc @@ -1,2 +1,4 @@ # Always typecheck against the latest releases, so no lockfile. package-lock=false +# Only the type declarations are used, so unpinned packages never run install scripts. +ignore-scripts=true diff --git a/.github/snippet-typecheck/package.json b/.github/snippet-typecheck/package.json index deb1c382..9977609f 100644 --- a/.github/snippet-typecheck/package.json +++ b/.github/snippet-typecheck/package.json @@ -1,7 +1,7 @@ { "name": "snippet-typecheck", "private": true, - "description": "Typechecks the docs' code snippets against the latest Checkly CLI. Install with `npm install` in this folder.", + "description": "Typechecks the docs' code snippets against the latest Checkly CLI. Install or refresh with `npm update` in this folder.", "type": "module", "scripts": { "check": "node typecheck-snippets.mjs ../..", diff --git a/.github/snippet-typecheck/typecheck-snippets.mjs b/.github/snippet-typecheck/typecheck-snippets.mjs index a4fbf243..3fd04084 100644 --- a/.github/snippet-typecheck/typecheck-snippets.mjs +++ b/.github/snippet-typecheck/typecheck-snippets.mjs @@ -7,7 +7,7 @@ // for other statements) is on the line before their fence. Snippets with a `/* More options... */` comment may omit required // props. Opt a block out with `{/* typecheck-skip */}` on the line before it. // -// Usage: npm install && npm run check (in .github/snippet-typecheck) +// Usage: npm update && npm run check (in .github/snippet-typecheck) import { readdirSync, readFileSync, existsSync } from 'node:fs'; import { dirname, join, relative, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -147,14 +147,14 @@ export function typecheckSnippets(snippets) { const errors = []; for (const [path, snippet] of virtual) { - const source = program.getSourceFile(path); - const syntactic = program.getSyntacticDiagnostics(source); + const sourceFile = program.getSourceFile(path); + const syntactic = program.getSyntacticDiagnostics(sourceFile); // Type errors on code that doesn't parse are noise; report the parse errors only. const partial = PARTIAL_MARKER.test(snippet.code); - const diagnostics = syntactic.length > 0 ? syntactic : program.getSemanticDiagnostics(source) + const diagnostics = syntactic.length > 0 ? syntactic : program.getSemanticDiagnostics(sourceFile) .filter(d => !isUnresolvedRelativeImport(d) && !(partial && isOnlyMissingProps(d)) && !(snippet.wrap && isPageContextName(d))); for (const d of diagnostics) { - const { line, character } = source.getLineAndCharacterOfPosition(d.start ?? 0); + const { line, character } = sourceFile.getLineAndCharacterOfPosition(d.start ?? 0); // Errors in generated wrapper lines point at the fragment's first line. errors.push({ file: snippet.file, diff --git a/package.json b/package.json index 358e054b..35cb0926 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "dev": "mint dev", "test:api-docs": "node --test .github/scripts/api-navigation.test.mjs", "check:links": "node .github/scripts/check-broken-links.mjs", - "check:snippets": "cd .github/snippet-typecheck && npm install --no-audit --no-fund --silent && npm run check --silent", - "test:snippets": "cd .github/snippet-typecheck && npm install --no-audit --no-fund --silent && npm test --silent", + "check:snippets": "cd .github/snippet-typecheck && npm update --no-audit --no-fund --silent && npm run check --silent", + "test:snippets": "cd .github/snippet-typecheck && npm update --no-audit --no-fund --silent && npm test --silent", "test:css-urls": "node --test .github/scripts/check-css-urls.test.mjs", "check:css-urls": "node .github/scripts/check-css-urls.mjs", "sync:api-group-tags": "node .github/scripts/sync-api-group-tags.mjs", From a590e5278324c83e708f2a92807396bc78c4e286 Mon Sep 17 00:00:00 2001 From: stefan judis Date: Fri, 30 Oct 2026 12:23:07 +0100 Subject: [PATCH 28/29] Revert unrelated formatting changes in construct pages --- constructs/overview.mdx | 6 +++--- constructs/retry-strategy.mdx | 2 +- constructs/sms-alert-channel.mdx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/constructs/overview.mdx b/constructs/overview.mdx index b7f907da..0137d551 100644 --- a/constructs/overview.mdx +++ b/constructs/overview.mdx @@ -5,12 +5,12 @@ sidebarTitle: 'Overview' canonical: 'https://www.checklyhq.com/docs/constructs/overview/' --- -import ChecklyConfigCodeBlock from '/snippets/checkly-config-example-code-block.mdx'; import JsTsNote from '/snippets/js-ts-note.mdx'; +import ChecklyConfigCodeBlock from '/snippets/checkly-config-example-code-block.mdx'; Every resource you create using the [Checkly CLI](/cli/overview/) is represented by a "construct": it's a class you import from `checkly/constructs`, -for instance an `ApiCheck` or `EmailAlertChannel`. A construct is the "as-code" representation of the eventual resource +for instance an `ApiCheck` or `EmailAlertChannel`. A construct is the "as-code" representation of the eventual resource created / deleted / updated on the Checkly cloud once you run `npx checkly deploy`. @@ -161,4 +161,4 @@ All resources you can create and manage using the Checkly CLI are derived from " [TypeScript classes](https://github.com/checkly/checkly-cli/tree/main/packages/cli/src/constructs). You can use standard JS/TS programming to use these constructs to create the monitoring setup of your -choice. Loops, variables, if-statements, file imports, extensions etc. [Here are some examples.](/constructs/dynamic-monitor-creation) +choice. Loops, variables, if-statements, file imports, extensions etc. [Here are some examples.](/constructs/dynamic-monitor-creation) \ No newline at end of file diff --git a/constructs/retry-strategy.mdx b/constructs/retry-strategy.mdx index 7dc773eb..fdd52221 100644 --- a/constructs/retry-strategy.mdx +++ b/constructs/retry-strategy.mdx @@ -350,7 +350,7 @@ When `sameRegion: false`, retries are attempted from different regions to help d -Apply the retry strategy only when the failure cause matches the specified condition. +Apply the retry strategy only when the failure cause matches the specified condition. **Usage:** diff --git a/constructs/sms-alert-channel.mdx b/constructs/sms-alert-channel.mdx index 653e59e3..a4f2caf9 100644 --- a/constructs/sms-alert-channel.mdx +++ b/constructs/sms-alert-channel.mdx @@ -49,9 +49,9 @@ const smsChannel = new SmsAlertChannel('sms-channel-1', { ### SMS Alert Channel Options -Phone number to send SMS notifications to. +Phone number to send SMS notifications to. -Each `SmsAlertChannel` supports only one phone number. Phone numbers need to be in [E.164 format](https://www.twilio.com/docs/glossary/what-e164). +Each `SmsAlertChannel` supports only one phone number. Phone numbers need to be in [E.164 format](https://www.twilio.com/docs/glossary/what-e164). We only support phone numbers from certain [countries and regions](/integrations/alerts/sms#supported-countries-and-regions). From 763cfc1b0cc7fc80b3a6950aa9a18fb2dfcdd9fb Mon Sep 17 00:00:00 2001 From: stefan judis Date: Fri, 30 Oct 2026 12:34:14 +0100 Subject: [PATCH 29/29] Make CLAUDE.md a symlink to AGENTS.md and document the snippet typecheck --- AGENTS.md | 15 ++++++-- CLAUDE.md | 104 +----------------------------------------------------- 2 files changed, 14 insertions(+), 105 deletions(-) mode change 100644 => 120000 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md index 41e10d5f..2f80c891 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,7 +54,6 @@ ## Writing standards - Second-person voice ("you") -- Prerequisites at start of procedural content - ALWAYS wrap prerequisites in an Accordion component - Test all code examples before publishing - Match style and formatting of existing pages - Include both basic and advanced use cases @@ -63,12 +62,21 @@ - Relative paths for internal links ## Component usage rules -- Prerequisites Should Always be wrapped in an Accordion component with title "Prerequisites" or "Before you begin" - Use Steps component for sequential procedures sparingly. - Don't use Cards to display information. Only for navigation on Overview type pages - Use CodeGroups and Dropdowns for code examples that show the same example in different languages - Use Note/Tip/Warning callouts appropriately +## Code snippet typecheck +CI typechecks Checkly CLI snippets in `.mdx` files against the latest `checkly` release. Run it locally with `npm run check:snippets`. + +- Complete snippets (with a `checkly` import or `require`) and fragments that use a checkly export (`new ApiCheck(`, `Frequency.EVERY_5M`) are checked automatically. +- `/* More options... */` marks a shortened snippet. Missing required props are allowed; wrong or unknown props still fail. +- Add a marker comment on the line before the code fence when you need one: + - `{/* typecheck-wrap: ApiCheck */}`: checks a property fragment like `request: {...}` inside that construct. + - `{/* typecheck-wrap */}`: checks a statement like `export default defineConfig(...)`, adding imports only. + - `{/* typecheck-skip */}`: opts the block out. Use it only when the snippet can't match the latest CLI. + ## CodeGroup Dropdown - Use `` for code examples that show the same functionality in different programming languages - The dropdown automatically creates a language selector based on the code block language identifiers @@ -86,6 +94,9 @@ - This replaces the older `` pattern for language-specific code examples +## Guides +- Any change under `guides/`, `samples/guides/`, or `images/guides/` follows the `guide-authoring` skill in `.claude/skills/guide-authoring/SKILL.md`: agent path first, tested samples, real screenshots, brand diagrams. + ## Git workflow - NEVER use --no-verify when committing - Ask how to handle uncommitted changes before starting diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 793079d4..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,103 +0,0 @@ -# Mintlify documentation - -## Working relationship -- You can push back on ideas-this can lead to better documentation. Cite sources and explain your reasoning when you do so -- ALWAYS ask for clarification rather than making assumptions -- NEVER lie, guess, or make up information - -## Project context -- Framework: Mintlify. https://mintlify.com/docs/llms.txt -- Format: MDX files with YAML frontmatter -- Config: docs.json for navigation, theme, settings. Tabs set top level navigation, Groups set sidebar navigation within Tabs. -- Components: We use Mintlify components and documentation. - -- Headers and text - -- Images and embeds - -- Lists and tables - -- Code - -- Reusable snippets - -- Accordions - -- Callouts - -- Cards - -- Columns - -- Code groups - -- Examples - -- Expandables - -- Fields - -- Frames - -- Icons - -- Mermaid - -- Panel - -- Steps - -- Tabs - -- Tooltips - -- Update - -## Content strategy -- Search for existing information before adding new content. Avoid duplication unless it is done for a strategic reason -- Check existing patterns for consistency -- Start by making the smallest reasonable changes -- Document just enough for user success - not too much. Don't be verbose. -- Prioritize accuracy and usability of information -- Make content evergreen - -## docs.json - -- Refer to the [docs.json schema](https://mintlify.com/docs.json) when building the docs.json file and site navigation -- Tabs --- Groups ---- Pages - -## Frontmatter requirements for pages -- title: Clear, descriptive page title -- sidebarTitle: Concise title for sidebar -- description: Concise summary for SEO/navigation - -## Writing standards -- Second-person voice ("you") -- Test all code examples before publishing -- Match style and formatting of existing pages -- Include both basic and advanced use cases -- Language tags on all code blocks -- Alt text on all images -- Relative paths for internal links - -## Component usage rules -- Use Steps component for sequential procedures sparingly. -- Don't use Cards to display information. Only for navigation on Overview type pages -- Use CodeGroups and Dropdowns for code examples that show the same example in different languages -- Use Note/Tip/Warning callouts appropriately - -## CodeGroup Dropdown -- Use `` for code examples that show the same functionality in different programming languages -- The dropdown automatically creates a language selector based on the code block language identifiers -- Example usage: - - -```typescript example.ts -// TypeScript code here -``` - -```javascript example.js -// JavaScript code here -``` - - -- This replaces the older `` pattern for language-specific code examples - -## Guides -- Any change under `guides/`, `samples/guides/`, or `images/guides/` follows the `guide-authoring` skill in `.claude/skills/guide-authoring/SKILL.md`: agent path first, tested samples, real screenshots, brand diagrams. - -## Git workflow -- NEVER use --no-verify when committing -- Ask how to handle uncommitted changes before starting -- Create a new branch when no clear branch exists for changes -- Commit frequently throughout development -- NEVER skip or disable pre-commit hooks - -## Do not -- Skip frontmatter on any MDX file -- Use absolute URLs for internal links -- Include untested code examples -- Make assumptions - always ask for clarification -- overuse components like Cards or Accordion -​ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000..47dc3e3d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file