diff --git a/bun.lock b/bun.lock index c55738d..c4a6068 100644 --- a/bun.lock +++ b/bun.lock @@ -5,13 +5,13 @@ "": { "name": "@corbits/webhooks", "devDependencies": { - "@intx/crypto": "0.4.0", - "@intx/db": "0.4.0", - "@intx/hub-api": "0.4.0", - "@intx/hub-common": "0.4.0", - "@intx/hub-sessions": "0.4.0", - "@intx/mime": "0.4.0", - "@intx/types": "0.4.0", + "@intx/crypto": "0.5.0", + "@intx/db": "0.5.0", + "@intx/hub-api": "0.5.0", + "@intx/hub-common": "0.5.0", + "@intx/hub-sessions": "0.5.0", + "@intx/mime": "0.5.0", + "@intx/types": "0.5.0", "@types/bun": "1.3.9", "drizzle-orm": "0.45.3", "hono": "4.11.9", @@ -21,13 +21,13 @@ "typescript": "5.9.3", }, "peerDependencies": { - "@intx/crypto": "^0.4.0", - "@intx/db": "^0.4.0", - "@intx/hub-api": "^0.4.0", - "@intx/hub-common": "^0.4.0", - "@intx/hub-sessions": "^0.4.0", - "@intx/mime": "^0.4.0", - "@intx/types": "^0.4.0", + "@intx/crypto": "^0.5.0", + "@intx/db": "^0.5.0", + "@intx/hub-api": "^0.5.0", + "@intx/hub-common": "^0.5.0", + "@intx/hub-sessions": "^0.5.0", + "@intx/mime": "^0.5.0", + "@intx/types": "^0.5.0", "drizzle-orm": "^0.45.1", "hono": "^4.11.9", "postgres": "^3.4.8", @@ -61,37 +61,37 @@ "@hono/standard-validator": ["@hono/standard-validator@0.2.3", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "hono": ">=3.9.0" } }, "sha512-bp9vHu6Va6SfMHC3D4ZLBbT/woi+AZ9CRdTXQu3kLJuLh2W/Gb9UO4hijS+BQAGFXi4EGpXdetxpzwTAawSVeg=="], - "@intx/agent": ["@intx/agent@0.4.0", "", { "dependencies": { "@intx/inference": "0.4.0", "@intx/log": "0.4.0", "@intx/mime": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29" } }, "sha512-qBlqDYnsaRMsug/lEKwUvPgQfjiwppTpfw5JaUh6pwKi0dGvckv3ugjJvLdHM052nTFMgLgOwo1LvbRjPZ5Uwg=="], + "@intx/agent": ["@intx/agent@0.5.0", "", { "dependencies": { "@intx/inference": "0.5.0", "@intx/log": "0.5.0", "@intx/mime": "0.5.0", "@intx/types": "0.5.0", "arktype": "^2.1.29" } }, "sha512-EWkRfduYJii67goq0cdO6qgRtV0aLe2jGk2aZJhurOivluy3tx0SlhiO2YaQmA4du+qBNzlMV9MMfKkmQ/zs+Q=="], - "@intx/authz": ["@intx/authz@0.4.0", "", { "dependencies": { "@intx/types": "0.4.0" } }, "sha512-A9x4EzcECnFjhDoqj0XjaOb1GaxRyJucXOuIbY+fcPluUuMCGFvExD6DJZwjJmIYdeCvL8i96gPkncu/fAR9qA=="], + "@intx/authz": ["@intx/authz@0.5.0", "", { "dependencies": { "@intx/types": "0.5.0" } }, "sha512-LJgm1H6oJ3lQTWc2jzzLpMNvMqmYBRUNHjUAcgTJEe2NdtUrrXUhvDT3hvJGljaslu/hSvcsdtamvY0d4wzpvw=="], - "@intx/crypto": ["@intx/crypto@0.4.0", "", { "dependencies": { "@intx/types": "0.4.0" } }, "sha512-4/qWypC90GevbV9u1i/93tn46jsXhj8wE1Pn+awg8/ECpwhHnhPLT5Uy423Arr9eGmRmF6HiMyXcEgH1Z9/Rkw=="], + "@intx/crypto": ["@intx/crypto@0.5.0", "", { "dependencies": { "@intx/types": "0.5.0" } }, "sha512-EX5dAQuazYbsqc51d9e9BkIxUEhGf4+9U3S91XHOg+OrHcjYRxZoFzgcrAHIJVK8Mqh0WzKhGTsY1g2r3iW9nw=="], - "@intx/db": ["@intx/db@0.4.0", "", { "dependencies": { "@intx/authz": "0.4.0", "@intx/crypto": "0.4.0", "@intx/hub-common": "0.4.0", "@intx/log": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "postgres": "^3.4.8" } }, "sha512-B26emrRrpIAlRygTWs6akVA6V/rN07v4YRxj3iTxzAOJVayIHSmPuPmKxqKN/AsBgLq6H1q94RP9sq05yb4twg=="], + "@intx/db": ["@intx/db@0.5.0", "", { "dependencies": { "@intx/authz": "0.5.0", "@intx/crypto": "0.5.0", "@intx/hub-common": "0.5.0", "@intx/log": "0.5.0", "@intx/types": "0.5.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "postgres": "^3.4.8" } }, "sha512-WIyWnUfNEchuhqAYqCma6ZZdRiRBxvcNyGkdZiGl4Vb1288BrFIjtok+VRA5wftWkFJ4aRpqyfgKcWWseW1G4w=="], - "@intx/hub-api": ["@intx/hub-api@0.4.0", "", { "dependencies": { "@hono/standard-validator": "^0.2.2", "@intx/agent": "0.4.0", "@intx/authz": "0.4.0", "@intx/crypto": "0.4.0", "@intx/db": "0.4.0", "@intx/hub-common": "0.4.0", "@intx/hub-sessions": "0.4.0", "@intx/log": "0.4.0", "@intx/mime": "0.4.0", "@intx/storage-isogit": "0.4.0", "@intx/types": "0.4.0", "@intx/workflow-deploy": "0.4.0", "arktype": "^2.1.29", "better-auth": "^1.4.18", "drizzle-orm": "^0.45.1", "hono": "^4.11.9", "hono-openapi": "^1.2.0", "isomorphic-git": "^1.27.2", "ssri": "^12.0.0" } }, "sha512-3Txw7Im38BdRujYeRlxgrzCdvOG1v92556AjNa/6WXSwgXt9Mn2fB4RoQrA6oUHcm10Y94WZh3IjaQsXFl7Qvg=="], + "@intx/hub-api": ["@intx/hub-api@0.5.0", "", { "dependencies": { "@hono/standard-validator": "^0.2.2", "@intx/agent": "0.5.0", "@intx/authz": "0.5.0", "@intx/crypto": "0.5.0", "@intx/db": "0.5.0", "@intx/hub-common": "0.5.0", "@intx/hub-sessions": "0.5.0", "@intx/log": "0.5.0", "@intx/mime": "0.5.0", "@intx/storage-isogit": "0.5.0", "@intx/types": "0.5.0", "@intx/workflow-deploy": "0.5.0", "arktype": "^2.1.29", "better-auth": "^1.4.18", "drizzle-orm": "^0.45.1", "hono": "^4.11.9", "hono-openapi": "^1.2.0", "isomorphic-git": "^1.27.2", "ssri": "^12.0.0" } }, "sha512-ObyGu0YV9w8g93LA6+a0tjGiI4saM1fwUi7JGiVGRJlQ2imD+iaIE8dyxzUdkeQN/ZmrGIQCdHt1Dg4+c0dQNA=="], - "@intx/hub-common": ["@intx/hub-common@0.4.0", "", { "dependencies": { "@intx/types": "0.4.0" } }, "sha512-4dcRX3kamqduf1Yil85GVsjXKnAnu6uqSYrAsl4vGpuV6R2DCy7z/PHd+DtIqk6TJrRdW7DtfkNXwSEc3dn2VQ=="], + "@intx/hub-common": ["@intx/hub-common@0.5.0", "", { "dependencies": { "@intx/types": "0.5.0" } }, "sha512-riLxc8a9ZkCaEDUxr3DWlrIaZ/WeLZ9HJmXU9MbcM9TEUfMR68F/EiuSGKwQRFDVH9WwRZB82WN6vuGWbAHksA=="], - "@intx/hub-sessions": ["@intx/hub-sessions@0.4.0", "", { "dependencies": { "@intx/agent": "0.4.0", "@intx/crypto": "0.4.0", "@intx/db": "0.4.0", "@intx/hub-common": "0.4.0", "@intx/log": "0.4.0", "@intx/mime": "0.4.0", "@intx/pack-transport": "0.4.0", "@intx/storage-isogit": "0.4.0", "@intx/tool-packaging": "0.4.0", "@intx/types": "0.4.0", "@intx/workflow": "0.4.0", "@intx/workflow-deploy": "0.4.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "isomorphic-git": "^1.27.2", "tar": "^7.5.1" } }, "sha512-/3nd/B/gENy3lq+MA2AR95tBu3Rkkh176XM+A8/mNMGnolPBGw+1JBUGGJ8gvdvAfo64dwRcEs3BI/VD7zFlPQ=="], + "@intx/hub-sessions": ["@intx/hub-sessions@0.5.0", "", { "dependencies": { "@intx/agent": "0.5.0", "@intx/crypto": "0.5.0", "@intx/db": "0.5.0", "@intx/hub-common": "0.5.0", "@intx/log": "0.5.0", "@intx/mime": "0.5.0", "@intx/pack-transport": "0.5.0", "@intx/storage-isogit": "0.5.0", "@intx/tool-packaging": "0.5.0", "@intx/types": "0.5.0", "@intx/workflow": "0.5.0", "@intx/workflow-deploy": "0.5.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "isomorphic-git": "^1.27.2", "tar": "^7.5.1" } }, "sha512-CgcXHnGtIw/Rjdhnry2TOSVvKeUh2x+XXvLJ/hrw86hBocvROUOFOykJ3/63Uft0OHPGKXf1D5AFPyc71P2arQ=="], - "@intx/inference": ["@intx/inference@0.4.0", "", { "dependencies": { "@intx/log": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29" } }, "sha512-cuaqCqotmjg0OzGUm8QmFJr1xX5wPVS0LeuhrxHsj0X3ImoCzVB4e/ttTc+DaP3K1tTMQ/8Q8HHCAPX36mOecQ=="], + "@intx/inference": ["@intx/inference@0.5.0", "", { "dependencies": { "@intx/log": "0.5.0", "@intx/types": "0.5.0", "arktype": "^2.1.29" } }, "sha512-Dr4HwV1RH+tlPjH5DqL5buymt3NdbX/v7gG1zEwSqUvQ044V8NBPJA7u7+o+w3zMrRwyUiW+n4d+lUooCVv3JA=="], - "@intx/log": ["@intx/log@0.4.0", "", { "dependencies": { "@logtape/hono": "^2.0.2", "@logtape/logtape": "^2.0.2" }, "peerDependencies": { "hono": "^4.0.0" }, "optionalPeers": ["hono"] }, "sha512-f1IPZ/9YpEqlA0I2UZPOlRJOTDoOFEZRwZoUVuw8DpgR1WatOMm4hA0E8o6Mtz+pA0ux7gVdls4y/JZcgypsfQ=="], + "@intx/log": ["@intx/log@0.5.0", "", { "dependencies": { "@logtape/hono": "^2.0.2", "@logtape/logtape": "^2.0.2" }, "peerDependencies": { "hono": "^4.0.0" }, "optionalPeers": ["hono"] }, "sha512-SxS1WM/wsxzWgAUBDE8RcBpoZSxNnVoRm21YnHr+uZeGzS1bkqc7zW41PzVAW9p6+EsoSZFN6dr5R3jcs4k9RA=="], - "@intx/mime": ["@intx/mime@0.4.0", "", { "dependencies": { "@intx/crypto": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29" } }, "sha512-sWrohF2uwVL5AZHbxIEUNiVUBhULff4XB7g6keCmyQWr296GKSvG/HmbihSXxiIvmmDzh9cl+6ZAJz/taxFNog=="], + "@intx/mime": ["@intx/mime@0.5.0", "", { "dependencies": { "@intx/crypto": "0.5.0", "@intx/types": "0.5.0", "arktype": "^2.1.29" } }, "sha512-8uVYEltQJD0/8FFQ6ilzruJ0ZOPLHWCKkyKz1srat3DrbiCsUE1V1YNYHSOCjhL/Htf6FmHuqm94ZmfwPZT8Yg=="], - "@intx/pack-transport": ["@intx/pack-transport@0.4.0", "", { "dependencies": { "@intx/types": "0.4.0" } }, "sha512-I+axd067ZFXaTRtr2zmBXl6/yU253wLc/YWEdXiPiqz06mIspR2BFJMbSXPzV4pM26n+1tv/9E5VNBQtdiYmSA=="], + "@intx/pack-transport": ["@intx/pack-transport@0.5.0", "", { "dependencies": { "@intx/types": "0.5.0" } }, "sha512-Ogxl3oeDEUDsers5lekhVzw2UyhAVrVAVBYZW3UVy7qBzICTFDBD2trAVkeswdBzVaHnvAx0GCwOrfl6Ji19gA=="], - "@intx/storage-isogit": ["@intx/storage-isogit@0.4.0", "", { "dependencies": { "@intx/log": "0.4.0", "@intx/mime": "0.4.0", "@intx/types": "0.4.0", "@isomorphic-git/lightning-fs": "4.7.0", "arktype": "^2.1.29", "buffer": "^6.0.3", "isomorphic-git": "^1.27.2" } }, "sha512-3H4dhUsWmAixLEBp79vq9NVUf6Z4++pKzaODWFEgNfhLX2WeV5J/t6soUamL6T/8eok/SDgQ/sZiZMiJ5kDKOw=="], + "@intx/storage-isogit": ["@intx/storage-isogit@0.5.0", "", { "dependencies": { "@intx/log": "0.5.0", "@intx/mime": "0.5.0", "@intx/types": "0.5.0", "@isomorphic-git/lightning-fs": "4.7.0", "arktype": "^2.1.29", "buffer": "^6.0.3", "isomorphic-git": "^1.27.2" } }, "sha512-9IsTX9zBhvE9U0sSu7rQozn6YU+jKIABnOlpTbqUsgpChyQsM2oq9RTmVm+sacwDrcCkxZFst9egWCH1nA9nkA=="], - "@intx/tool-packaging": ["@intx/tool-packaging@0.4.0", "", { "dependencies": { "@intx/agent": "0.4.0", "@intx/log": "0.4.0", "@intx/storage-isogit": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29", "isomorphic-git": "^1.27.2", "npm-package-arg": "^12.0.2", "npm-pick-manifest": "^10.0.0", "npm-registry-fetch": "^19.0.0", "semver": "^7.7.2", "ssri": "^12.0.0", "tar": "^7.5.1" } }, "sha512-eBZIbGUcEBp0ppMCceA1PPd75LvXpUyWitqTIu7AsLxRNlU9gbE1hymWPXnhUKnt3LgSlHUi959Ehd6jG6mR7g=="], + "@intx/tool-packaging": ["@intx/tool-packaging@0.5.0", "", { "dependencies": { "@intx/agent": "0.5.0", "@intx/log": "0.5.0", "@intx/storage-isogit": "0.5.0", "@intx/types": "0.5.0", "arktype": "^2.1.29", "isomorphic-git": "^1.27.2", "npm-package-arg": "^12.0.2", "npm-pick-manifest": "^10.0.0", "npm-registry-fetch": "^19.0.0", "semver": "^7.7.2", "ssri": "^12.0.0", "tar": "^7.5.1" } }, "sha512-Jf1XskGsN41q2/mBQNQaf410YeqAXNdXI9+hEP3aq3vmjtSUpNr4juRoRdd9p6otDxMcP9oLLZd8FdfP/dYCrA=="], - "@intx/types": ["@intx/types@0.4.0", "", { "dependencies": { "arktype": "^2.1.29", "semver": "^7.7.2" } }, "sha512-nJ2fcmskMOZNMRfbHs5ueKpCANHNttoL+sZgIoFaVUF/QLpFWfVp0YV72CQAaa9bVv9j5kRSwtSOCCGSlwQ6Dw=="], + "@intx/types": ["@intx/types@0.5.0", "", { "dependencies": { "arktype": "^2.1.29", "semver": "^7.7.2" } }, "sha512-FZu96zH9XqEgpOahXbXUPkg8qAV0TG4JggrE5A4ZN0jdiEB6n06YM6CPv+REuoKoYF9UIHviwltV9ZbT2D1rdQ=="], - "@intx/workflow": ["@intx/workflow@0.4.0", "", { "dependencies": { "@intx/agent": "0.4.0", "@intx/inference": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29" } }, "sha512-F5Is/lyKb4/WguAVYMDXwtI4ddUvqXbg34rcM6hPUOqupJHpbbD9+ZK/6TDfvbCiEgginbTVwMmNj6Fyg8vU+Q=="], + "@intx/workflow": ["@intx/workflow@0.5.0", "", { "dependencies": { "@intx/agent": "0.5.0", "@intx/inference": "0.5.0", "@intx/types": "0.5.0", "arktype": "^2.1.29" } }, "sha512-yEIrIWxZ3okiGCXt99MkHdarhVff8fhA90ynrRcaJoLXCYU5zFsmhooLcEzmKUHRWosLalnuhJvpnJIdWed/GA=="], - "@intx/workflow-deploy": ["@intx/workflow-deploy@0.4.0", "", { "dependencies": { "@intx/agent": "0.4.0", "@intx/tool-packaging": "0.4.0", "@intx/types": "0.4.0", "@intx/workflow": "0.4.0" } }, "sha512-TSLg9lPZvJ+leg2n0I/SWxZjcNQtzsH2oKLD04ptEsBZcbIuMINsQeZBmYV5Brdovy0J/SrWZyrOJ8lc+k/Fdw=="], + "@intx/workflow-deploy": ["@intx/workflow-deploy@0.5.0", "", { "dependencies": { "@intx/agent": "0.5.0", "@intx/authz": "0.5.0", "@intx/types": "0.5.0", "@intx/workflow": "0.5.0" } }, "sha512-AtgKPq1BJ79ywp30vuCINbwy0Lajx4KXGyOvt/4M5/Mwu/2KETK2A0JdanEaQIhZqRSvnQ0HezvMm6WC4/noRQ=="], "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], diff --git a/e2e/helpers.ts b/e2e/helpers.ts index 221bd47..4894ae5 100644 --- a/e2e/helpers.ts +++ b/e2e/helpers.ts @@ -99,7 +99,7 @@ export const testCredentialCipher = createEnvKeyCredentialCipher( export function recordingRouter() { const mail: Parameters[] = []; const router: HookRouter = { - routeMail: (...args) => { + routeMail: async (...args) => { mail.push(args); return true; }, diff --git a/e2e/hooks.test.ts b/e2e/hooks.test.ts index 1f0ff6a..04f025b 100644 --- a/e2e/hooks.test.ts +++ b/e2e/hooks.test.ts @@ -31,11 +31,11 @@ import { type TestDb, } from "./helpers.js"; -const TENANT = "tnt_e2e"; +const TENANT = "tnte2e"; const CREATOR = "prn_creator"; const DEFINITION = "wfd_hook"; const DEPLOYMENT = "run_hook"; -const ADDRESS = "run_hook@tnt_e2e.example.test"; +const ADDRESS = "run_hook@tnte2e.example.test"; const HOOK = "crd_hook"; const SECRET = "whsec_c2VjcmV0LWtleS1ieXRlcw=="; @@ -80,6 +80,7 @@ async function seedDeployment(db: TestDb["db"]): Promise { anchorRunId: DEPLOYMENT, definitionId: DEFINITION, address: ADDRESS, + publicKey: "pk_hook", status: "deployed", }); await db.insert(provider).values({ @@ -230,10 +231,10 @@ describe.skipIf(!harnessDbAvailable())( test("the tenant-scoped name path resolves only inside that tenant", async () => { const recorded = recordingRouter(); const app = mountHookRoutes({ db: db(), router: recorded.router }); - await seedTenant(db(), "tnt_other"); + await seedTenant(db(), "tntother"); const body = `{"text":"hi"}`; - const miss = await app.request("/api/hooks/tnt_other/my-hook", { + const miss = await app.request("/api/hooks/tntother/my-hook", { method: "POST", headers: await standardWebhooksHeaders(body), body, diff --git a/package.json b/package.json index 81f63c5..9381a4e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@corbits/webhooks", - "version": "0.3.1", + "version": "0.3.2", "description": "Receive signed webhooks (Slack, Standard Webhooks, bearer) and start a workflow run.", "keywords": [ "corbits", @@ -53,13 +53,13 @@ "check": "bun run typecheck && bun run lint && bun run format:check && bun run test" }, "devDependencies": { - "@intx/crypto": "0.4.0", - "@intx/db": "0.4.0", - "@intx/hub-api": "0.4.0", - "@intx/hub-common": "0.4.0", - "@intx/hub-sessions": "0.4.0", - "@intx/mime": "0.4.0", - "@intx/types": "0.4.0", + "@intx/crypto": "0.5.0", + "@intx/db": "0.5.0", + "@intx/hub-api": "0.5.0", + "@intx/hub-common": "0.5.0", + "@intx/hub-sessions": "0.5.0", + "@intx/mime": "0.5.0", + "@intx/types": "0.5.0", "@types/bun": "1.3.9", "drizzle-orm": "0.45.3", "hono": "4.11.9", @@ -69,13 +69,13 @@ "typescript": "5.9.3" }, "peerDependencies": { - "@intx/crypto": "^0.4.0", - "@intx/db": "^0.4.0", - "@intx/hub-api": "^0.4.0", - "@intx/hub-common": "^0.4.0", - "@intx/hub-sessions": "^0.4.0", - "@intx/mime": "^0.4.0", - "@intx/types": "^0.4.0", + "@intx/crypto": "^0.5.0", + "@intx/db": "^0.5.0", + "@intx/hub-api": "^0.5.0", + "@intx/hub-common": "^0.5.0", + "@intx/hub-sessions": "^0.5.0", + "@intx/mime": "^0.5.0", + "@intx/types": "^0.5.0", "drizzle-orm": "^0.45.1", "hono": "^4.11.9", "postgres": "^3.4.8" diff --git a/src/deliver.test.ts b/src/deliver.test.ts index b8a34fa..a4830c1 100644 --- a/src/deliver.test.ts +++ b/src/deliver.test.ts @@ -42,7 +42,7 @@ async function durableSystemSender() { function recordingRouter() { const calls: Parameters[] = []; const router: HookRouter = { - routeMail: (...args) => { + routeMail: async (...args) => { calls.push(args); return true; }, @@ -165,7 +165,7 @@ describe("createRunTriggerDeliverer", () => { test("a dead run address fails with its run identity, not a bare string", async () => { const sender = await durableSystemSender(); const recorded = recordingRouter(); - recorded.router.routeMail = () => false; + recorded.router.routeMail = async () => false; const error = await deliverer(recorded.router, sender.sender) .to(ADDRESS, "tick", "tnt_1", undefined) .then( diff --git a/src/deliver.ts b/src/deliver.ts index 3a84251..7154ff3 100644 --- a/src/deliver.ts +++ b/src/deliver.ts @@ -83,6 +83,8 @@ export function createRunTriggerDeliverer( throw new Error("destination is not a workflow deployment"); case "materialized": break; + case "notReady": + throw new Error("destination run grants are not ready"); default: grants satisfies never; } diff --git a/src/hooks.ts b/src/hooks.ts index 6d9442e..dfde3b8 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -60,7 +60,7 @@ async function handle(c: Context, opts: HookAppOptions) { } const tenantHint = - (pathTenant?.startsWith("tnt_") ? pathTenant : undefined) ?? + pathTenant ?? emptyToUndef(c.req.header("x-tenant-id")) ?? emptyToUndef(c.req.query("tenant"));