zen: rate limit

This commit is contained in:
Frank
2025-11-08 10:15:35 -05:00
parent 9cd465f9c0
commit 30b1ae5d4b
29 changed files with 620 additions and 419 deletions

View File

@@ -11,7 +11,7 @@
"@tsconfig/bun": "catalog:", "@tsconfig/bun": "catalog:",
"husky": "9.1.7", "husky": "9.1.7",
"prettier": "3.6.2", "prettier": "3.6.2",
"sst": "3.17.22", "sst": "3.17.23",
"turbo": "2.5.6", "turbo": "2.5.6",
}, },
}, },
@@ -106,7 +106,10 @@
"@cloudflare/workers-types": "catalog:", "@cloudflare/workers-types": "catalog:",
}, },
"devDependencies": { "devDependencies": {
"@cloudflare/workers-types": "catalog:",
"@tsconfig/node22": "22.0.2", "@tsconfig/node22": "22.0.2",
"@types/node": "catalog:",
"cloudflare": "5.2.0",
}, },
}, },
"packages/desktop": { "packages/desktop": {
@@ -1432,6 +1435,8 @@
"@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], "@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="],
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
"@types/promise.allsettled": ["@types/promise.allsettled@1.0.6", "", {}, "sha512-wA0UT0HeT2fGHzIFV9kWpYz5mdoyLxKrTgMdZQM++5h6pYAFH73HXcQhefg24nD1yivUFEn5KU+EF4b+CXJ4Wg=="], "@types/promise.allsettled": ["@types/promise.allsettled@1.0.6", "", {}, "sha512-wA0UT0HeT2fGHzIFV9kWpYz5mdoyLxKrTgMdZQM++5h6pYAFH73HXcQhefg24nD1yivUFEn5KU+EF4b+CXJ4Wg=="],
"@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="],
@@ -1518,6 +1523,8 @@
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
"ai": ["ai@5.0.8", "", { "dependencies": { "@ai-sdk/gateway": "1.0.4", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.1", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-qbnhj046UvG30V1S5WhjBn+RBGEAmi8PSZWqMhRsE3EPxvO5BcePXTZFA23e9MYyWS9zr4Vm8Mv3wQXwLmtIBw=="], "ai": ["ai@5.0.8", "", { "dependencies": { "@ai-sdk/gateway": "1.0.4", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.1", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-qbnhj046UvG30V1S5WhjBn+RBGEAmi8PSZWqMhRsE3EPxvO5BcePXTZFA23e9MYyWS9zr4Vm8Mv3wQXwLmtIBw=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
@@ -1742,6 +1749,8 @@
"clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="], "clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="],
"cloudflare": ["cloudflare@5.2.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-dVzqDpPFYR9ApEC9e+JJshFJZXcw4HzM8W+3DHzO5oy9+8rLC53G7x6fEf9A7/gSuSCxuvndzui5qJKftfIM9A=="],
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
"cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="],
@@ -2068,7 +2077,11 @@
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
"form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="], "form-data": ["form-data@4.0.4", "", { "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" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
"form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="],
"formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="],
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
@@ -2258,6 +2271,8 @@
"human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
"husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="],
"i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="], "i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="],
@@ -2716,6 +2731,8 @@
"node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="], "node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="],
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
@@ -3178,23 +3195,23 @@
"sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="],
"sst": ["sst@3.17.22", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.22", "sst-darwin-x64": "3.17.22", "sst-linux-arm64": "3.17.22", "sst-linux-x64": "3.17.22", "sst-linux-x86": "3.17.22", "sst-win32-arm64": "3.17.22", "sst-win32-x64": "3.17.22", "sst-win32-x86": "3.17.22" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-C+XMTbm6fx+7eT+ESAMATqG7qV7+pyVfxYQb6osdH3jd4u91QW1VU/xlEru+RU1rs1ZE58ixXdRP75UGPn+gog=="], "sst": ["sst@3.17.23", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.23", "sst-darwin-x64": "3.17.23", "sst-linux-arm64": "3.17.23", "sst-linux-x64": "3.17.23", "sst-linux-x86": "3.17.23", "sst-win32-arm64": "3.17.23", "sst-win32-x64": "3.17.23", "sst-win32-x86": "3.17.23" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-TwKgUgDnZdc1Swe+bvCNeyO4dQnYz5cTodMpYj3jlXZdK9/KNz0PVxT1f0u5E76i1pmilXrUBL/f7iiMPw4RDg=="],
"sst-darwin-arm64": ["sst-darwin-arm64@3.17.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B2pKq1dWc60+7HfXQ6/9etskxxNv9axxlQKveCLQAuG2a3mmtv2/jcR0Ch3mvSTGtW+KfhzUXda2kj7nZ/phBA=="], "sst-darwin-arm64": ["sst-darwin-arm64@3.17.23", "", { "os": "darwin", "cpu": "arm64" }, "sha512-R6kvmF+rUideOoU7KBs2SdvrIupoE+b+Dor/eq9Uo4Dojj7KvYDZI/EDm8sSCbbcx/opiWeyNqKtlnLEdCxE6g=="],
"sst-darwin-x64": ["sst-darwin-x64@3.17.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-flikYqXvhwwrS6x2FDOde+MQODHaZCIbUkVHYO3/gYo99rbAMQ8VpC/3LXnmnPEQkLOwWCSzLp4S4F9nG/PW2g=="], "sst-darwin-x64": ["sst-darwin-x64@3.17.23", "", { "os": "darwin", "cpu": "x64" }, "sha512-WW4P1S35iYCifQXxD+sE3wuzcN+LHLpuKMaNoaBqEcWGZnH3IPaDJ7rpLF0arkDAo/z3jZmWWzOCkr0JuqJ8vQ=="],
"sst-linux-arm64": ["sst-linux-arm64@3.17.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-+pyD8Oej9js8XeCCebiEIde02vC5hc+bLl2/jR02K+9gYkGVJ6n5bkT8AlR8zWdS4FJKPyeJYUfjliT1T33j+g=="], "sst-linux-arm64": ["sst-linux-arm64@3.17.23", "", { "os": "linux", "cpu": "arm64" }, "sha512-TjtNqgIh7RlAWgPLFCAt0mXvIB+J7WjmRvIRrAdX0mXsndOiBJ/DMOgXSLVsIWHCfPj8MIEot/hWpnJgXgIeag=="],
"sst-linux-x64": ["sst-linux-x64@3.17.22", "", { "os": "linux", "cpu": "x64" }, "sha512-A5p941edP9wgfgsbLUMeEPvi9JExj0OSaxgtFAC6/6BYoW4zruGAPzq206Ln6dNYP3gRdo5TJbSjio3F0ot8qg=="], "sst-linux-x64": ["sst-linux-x64@3.17.23", "", { "os": "linux", "cpu": "x64" }, "sha512-qdqJiEbYfCjZlI3F/TA6eoIU7JXVkEEI/UMILNf2JWhky0KQdCW2Xyz+wb6c0msVJCWdUM/uj+1DaiP2eXvghw=="],
"sst-linux-x86": ["sst-linux-x86@3.17.22", "", { "os": "linux", "cpu": "none" }, "sha512-pFDIi+ZwH8GOvy5He9wsbAjRGf/sTGhGE/V480w0A6itb9BC4jQ9sblJkk3Jx/fP2g27pKN2RNz+ifOU+GrUYQ=="], "sst-linux-x86": ["sst-linux-x86@3.17.23", "", { "os": "linux", "cpu": "none" }, "sha512-aGmUujIvoNlmAABEGsOgfY1rxD9koC6hN8bnTLbDI+oI/u/zjHYh50jsbL0p3TlaHpwF/lxP3xFSuT6IKp+KgA=="],
"sst-win32-arm64": ["sst-win32-arm64@3.17.22", "", { "os": "win32", "cpu": "arm64" }, "sha512-9KaIrk+Z6hLDNi9GShf9NLrZi9jC/NNGpUAn6HvTXr8c6HUyQzg6takMH8nrISGCPn92y+IYWqdglaqbgnJTog=="], "sst-win32-arm64": ["sst-win32-arm64@3.17.23", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZxdkGqYDrrZGz98rijDCN+m5yuCcwD6Bc9/6hubLsvdpNlVorUqzpg801Ec97xSK0nIC9g6pNiRyxAcsQQstUg=="],
"sst-win32-x64": ["sst-win32-x64@3.17.22", "", { "os": "win32", "cpu": "x64" }, "sha512-cvzyet4octGHK7w05jPUSPmUdlAWyh8IzjB8Pcs873K9AUGJEtQCftOKZjXaFdIG9DTvFWCCBi9zdzClxT9jJg=="], "sst-win32-x64": ["sst-win32-x64@3.17.23", "", { "os": "win32", "cpu": "x64" }, "sha512-yc9cor4MS49Ccy2tQCF1tf6M81yLeSGzGL+gjhUxpVKo2pN3bxl3w70eyU/mTXSEeyAmG9zEfbt6FNu4sy5cUA=="],
"sst-win32-x86": ["sst-win32-x86@3.17.22", "", { "os": "win32", "cpu": "none" }, "sha512-ol5icDJuHzG+AjbGbCIQoF8z3oiikTF9CtccdK/udqEF861DnngWzM99IY5TJvmJlN+38yOV0MY4XI5hM6SEQA=="], "sst-win32-x86": ["sst-win32-x86@3.17.23", "", { "os": "win32", "cpu": "none" }, "sha512-DIp3s54IpNAfdYjSRt6McvkbEPQDMxUu6RUeRAd2C+FcTJgTloon/ghAPQBaDgu2VoVgymjcJARO/XyfKcCLOQ=="],
"stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="],
@@ -3480,6 +3497,8 @@
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
"web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="],
"web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="], "web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="],
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
@@ -3754,6 +3773,8 @@
"@slack/web-api/eventemitter3": ["eventemitter3@3.1.2", "", {}, "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="], "@slack/web-api/eventemitter3": ["eventemitter3@3.1.2", "", {}, "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="],
"@slack/web-api/form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="],
"@slack/web-api/p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="], "@slack/web-api/p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="],
"@solidjs/start/shiki": ["shiki@1.29.2", "", { "dependencies": { "@shikijs/core": "1.29.2", "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/langs": "1.29.2", "@shikijs/themes": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg=="], "@solidjs/start/shiki": ["shiki@1.29.2", "", { "dependencies": { "@shikijs/core": "1.29.2", "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/langs": "1.29.2", "@shikijs/themes": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg=="],
@@ -3814,8 +3835,6 @@
"astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"axios/form-data": ["form-data@4.0.4", "", { "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" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
"babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
"babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="], "babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="],
@@ -4350,6 +4369,8 @@
"@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], "@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"@slack/web-api/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"@slack/web-api/p-queue/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], "@slack/web-api/p-queue/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="],
"@slack/web-api/p-queue/p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="], "@slack/web-api/p-queue/p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="],
@@ -4402,8 +4423,6 @@
"astro/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], "astro/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"axios/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.4", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA=="], "babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.4", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA=="],
"babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], "babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="],
@@ -4700,6 +4719,8 @@
"@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
"@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="],
"@vercel/nft/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "@vercel/nft/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
@@ -4708,8 +4729,6 @@
"archiver-utils/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "archiver-utils/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"axios/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], "babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],

2
github/sst-env.d.ts vendored
View File

@@ -6,4 +6,4 @@
/// <reference path="../sst-env.d.ts" /> /// <reference path="../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -106,6 +106,7 @@ const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", { const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", {
properties: { value: stripeWebhook.secret }, properties: { value: stripeWebhook.secret },
}) })
const gatewayKv = new sst.cloudflare.Kv("GatewayKv")
//////////////// ////////////////
// CONSOLE // CONSOLE
@@ -136,6 +137,16 @@ new sst.cloudflare.x.SolidStart("Console", {
EMAILOCTOPUS_API_KEY, EMAILOCTOPUS_API_KEY,
AWS_SES_ACCESS_KEY_ID, AWS_SES_ACCESS_KEY_ID,
AWS_SES_SECRET_ACCESS_KEY, AWS_SES_SECRET_ACCESS_KEY,
...($dev
? [
new sst.Secret(
"CLOUDFLARE_DEFAULT_ACCOUNT_ID",
process.env.CLOUDFLARE_DEFAULT_ACCOUNT_ID!,
),
new sst.Secret("CLOUDFLARE_API_TOKEN", process.env.CLOUDFLARE_API_TOKEN!),
]
: []),
gatewayKv,
], ],
environment: { environment: {
//VITE_DOCS_URL: web.url.apply((url) => url!), //VITE_DOCS_URL: web.url.apply((url) => url!),

View File

@@ -52,7 +52,7 @@
"@tsconfig/bun": "catalog:", "@tsconfig/bun": "catalog:",
"husky": "9.1.7", "husky": "9.1.7",
"prettier": "3.6.2", "prettier": "3.6.2",
"sst": "3.17.22", "sst": "3.17.23",
"turbo": "2.5.6" "turbo": "2.5.6"
}, },
"dependencies": { "dependencies": {

View File

@@ -3,3 +3,4 @@ export class CreditsError extends Error {}
export class MonthlyLimitError extends Error {} export class MonthlyLimitError extends Error {}
export class UserLimitError extends Error {} export class UserLimitError extends Error {}
export class ModelError extends Error {} export class ModelError extends Error {}
export class RateLimitError extends Error {}

View File

@@ -12,14 +12,14 @@ import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js" import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js"
import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js" import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js"
import { logger } from "./logger" import { logger } from "./logger"
import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError } from "./error" import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError, RateLimitError } from "./error"
import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider" import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider"
import { anthropicHelper } from "./provider/anthropic" import { anthropicHelper } from "./provider/anthropic"
import { openaiHelper } from "./provider/openai" import { openaiHelper } from "./provider/openai"
import { oaCompatHelper } from "./provider/openai-compatible" import { oaCompatHelper } from "./provider/openai-compatible"
import { createRateLimiter } from "./rateLimiter"
type ZenData = Awaited<ReturnType<typeof ZenData.list>> type ZenData = Awaited<ReturnType<typeof ZenData.list>>
type Model = ZenData["models"][string]
export async function handler( export async function handler(
input: APIEvent, input: APIEvent,
@@ -28,6 +28,10 @@ export async function handler(
parseApiKey: (headers: Headers) => string | undefined parseApiKey: (headers: Headers) => string | undefined
}, },
) { ) {
type AuthInfo = Awaited<ReturnType<typeof authenticate>>
type ModelInfo = Awaited<ReturnType<typeof validateModel>>
type ProviderInfo = Awaited<ReturnType<typeof selectProvider>>
const FREE_WORKSPACES = [ const FREE_WORKSPACES = [
"wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank "wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank
"wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench "wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench
@@ -35,6 +39,7 @@ export async function handler(
try { try {
const body = await input.request.json() const body = await input.request.json()
const ip = input.request.headers.get("x-real-ip") ?? ""
logger.metric({ logger.metric({
is_tream: !!body.stream, is_tream: !!body.stream,
session: input.request.headers.get("x-opencode-session"), session: input.request.headers.get("x-opencode-session"),
@@ -42,9 +47,11 @@ export async function handler(
}) })
const zenData = ZenData.list() const zenData = ZenData.list()
const modelInfo = validateModel(zenData, body.model) const modelInfo = validateModel(zenData, body.model)
const providerInfo = selectProvider(zenData, modelInfo, input.request.headers.get("x-real-ip") ?? "") const providerInfo = selectProvider(zenData, modelInfo, ip)
const authInfo = await authenticate(modelInfo, providerInfo) const authInfo = await authenticate(modelInfo, providerInfo)
validateBilling(modelInfo, authInfo) const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip)
await rateLimiter?.check()
validateBilling(authInfo, modelInfo)
validateModelSettings(authInfo) validateModelSettings(authInfo)
updateProviderKey(authInfo, providerInfo) updateProviderKey(authInfo, providerInfo)
logger.metric({ provider: providerInfo.id }) logger.metric({ provider: providerInfo.id })
@@ -59,7 +66,7 @@ export async function handler(
}), }),
) )
logger.debug("REQUEST URL: " + reqUrl) logger.debug("REQUEST URL: " + reqUrl)
logger.debug("REQUEST: " + reqBody) logger.debug("REQUEST: " + reqBody.substring(0, 300) + "...")
const res = await fetch(reqUrl, { const res = await fetch(reqUrl, {
method: "POST", method: "POST",
headers: (() => { headers: (() => {
@@ -84,9 +91,6 @@ export async function handler(
} }
} }
logger.debug("STATUS: " + res.status + " " + res.statusText) logger.debug("STATUS: " + res.status + " " + res.statusText)
if (res.status === 400 || res.status === 503) {
logger.debug("RESPONSE: " + (await res.text()))
}
// Handle non-streaming response // Handle non-streaming response
if (!body.stream) { if (!body.stream) {
@@ -95,6 +99,7 @@ export async function handler(
const body = JSON.stringify(responseConverter(json)) const body = JSON.stringify(responseConverter(json))
logger.metric({ response_length: body.length }) logger.metric({ response_length: body.length })
logger.debug("RESPONSE: " + body) logger.debug("RESPONSE: " + body)
await rateLimiter?.track()
await trackUsage(authInfo, modelInfo, providerInfo, json.usage) await trackUsage(authInfo, modelInfo, providerInfo, json.usage)
await reload(authInfo) await reload(authInfo)
return new Response(body, { return new Response(body, {
@@ -123,6 +128,7 @@ export async function handler(
response_length: responseLength, response_length: responseLength,
"timestamp.last_byte": Date.now(), "timestamp.last_byte": Date.now(),
}) })
await rateLimiter?.track()
const usage = usageParser.retrieve() const usage = usageParser.retrieve()
if (usage) { if (usage) {
await trackUsage(authInfo, modelInfo, providerInfo, usage) await trackUsage(authInfo, modelInfo, providerInfo, usage)
@@ -197,6 +203,15 @@ export async function handler(
{ status: 401 }, { status: 401 },
) )
if (error instanceof RateLimitError)
return new Response(
JSON.stringify({
type: "error",
error: { type: error.constructor.name, message: error.message },
}),
{ status: 429 },
)
return new Response( return new Response(
JSON.stringify({ JSON.stringify({
type: "error", type: "error",
@@ -221,8 +236,8 @@ export async function handler(
return { id: modelId, ...modelData } return { id: modelId, ...modelData }
} }
function selectProvider(zenData: ZenData, model: Awaited<ReturnType<typeof validateModel>>, ip: string) { function selectProvider(zenData: ZenData, modelInfo: ModelInfo, ip: string) {
const providers = model.providers const providers = modelInfo.providers
.filter((provider) => !provider.disabled) .filter((provider) => !provider.disabled)
.flatMap((provider) => Array<typeof provider>(provider.weight ?? 1).fill(provider)) .flatMap((provider) => Array<typeof provider>(provider.weight ?? 1).fill(provider))
@@ -235,22 +250,22 @@ export async function handler(
throw new ModelError(`Provider ${provider.id} not supported`) throw new ModelError(`Provider ${provider.id} not supported`)
} }
const format = zenData.providers[provider.id].format
return { return {
...provider, ...provider,
...zenData.providers[provider.id], ...zenData.providers[provider.id],
...(format === "anthropic" ? anthropicHelper : format === "openai" ? openaiHelper : oaCompatHelper), ...(() => {
const format = zenData.providers[provider.id].format
if (format === "anthropic") return anthropicHelper
if (format === "openai") return openaiHelper
return oaCompatHelper
})(),
} }
} }
async function authenticate( async function authenticate(modelInfo: ModelInfo, providerInfo: ProviderInfo) {
model: Awaited<ReturnType<typeof validateModel>>,
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
) {
const apiKey = opts.parseApiKey(input.request.headers) const apiKey = opts.parseApiKey(input.request.headers)
if (!apiKey) { if (!apiKey) {
if (model.allowAnonymous) return if (modelInfo.allowAnonymous) return
throw new AuthError("Missing API key.") throw new AuthError("Missing API key.")
} }
@@ -282,7 +297,7 @@ export async function handler(
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
.innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID)) .innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID))
.innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID))) .innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)))
.leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id))) .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, modelInfo.id)))
.leftJoin( .leftJoin(
ProviderTable, ProviderTable,
and(eq(ProviderTable.workspaceID, KeyTable.workspaceID), eq(ProviderTable.provider, providerInfo.id)), and(eq(ProviderTable.workspaceID, KeyTable.workspaceID), eq(ProviderTable.provider, providerInfo.id)),
@@ -308,11 +323,11 @@ export async function handler(
} }
} }
function validateBilling(model: Model, authInfo: Awaited<ReturnType<typeof authenticate>>) { function validateBilling(authInfo: AuthInfo, modelInfo: ModelInfo) {
if (!authInfo) return if (!authInfo) return
if (authInfo.provider?.credentials) return if (authInfo.provider?.credentials) return
if (authInfo.isFree) return if (authInfo.isFree) return
if (model.allowAnonymous) return if (modelInfo.allowAnonymous) return
const billing = authInfo.billing const billing = authInfo.billing
if (!billing.paymentMethodID) if (!billing.paymentMethodID)
@@ -356,26 +371,18 @@ export async function handler(
} }
} }
function validateModelSettings(authInfo: Awaited<ReturnType<typeof authenticate>>) { function validateModelSettings(authInfo: AuthInfo) {
if (!authInfo) return if (!authInfo) return
if (authInfo.isDisabled) throw new ModelError("Model is disabled") if (authInfo.isDisabled) throw new ModelError("Model is disabled")
} }
function updateProviderKey( function updateProviderKey(authInfo: AuthInfo, providerInfo: ProviderInfo) {
authInfo: Awaited<ReturnType<typeof authenticate>>,
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
) {
if (!authInfo) return if (!authInfo) return
if (!authInfo.provider?.credentials) return if (!authInfo.provider?.credentials) return
providerInfo.apiKey = authInfo.provider.credentials providerInfo.apiKey = authInfo.provider.credentials
} }
async function trackUsage( async function trackUsage(authInfo: AuthInfo, modelInfo: ModelInfo, providerInfo: ProviderInfo, usage: any) {
authInfo: Awaited<ReturnType<typeof authenticate>>,
modelInfo: ReturnType<typeof validateModel>,
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
usage: any,
) {
const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } = const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } =
providerInfo.normalizeUsage(usage) providerInfo.normalizeUsage(usage)
@@ -483,7 +490,7 @@ export async function handler(
) )
} }
async function reload(authInfo: Awaited<ReturnType<typeof authenticate>>) { async function reload(authInfo: AuthInfo) {
if (!authInfo) return if (!authInfo) return
if (authInfo.isFree) return if (authInfo.isFree) return
if (authInfo.provider?.credentials) return if (authInfo.provider?.credentials) return

View File

@@ -0,0 +1,36 @@
import { Resource } from "@opencode-ai/console-resource"
import { RateLimitError } from "./error"
import { logger } from "./logger"
export function createRateLimiter(model: string, limit: number | undefined, ip: string) {
if (!limit) return
const now = Date.now()
const currKey = `usage:${ip}:${model}:${buildYYYYMMDDHH(now)}`
const prevKey = `usage:${ip}:${model}:${buildYYYYMMDDHH(now - 3_600_000)}`
let currRate: number
let prevRate: number
return {
track: async () => {
await Resource.GatewayKv.put(currKey, currRate + 1, { expirationTtl: 3600 })
},
check: async () => {
const values = await Resource.GatewayKv.get([currKey, prevKey])
const prevValue = values?.get(prevKey)
const currValue = values?.get(currKey)
prevRate = prevValue ? parseInt(prevValue) : 0
currRate = currValue ? parseInt(currValue) : 0
logger.debug(`rate limit ${model} prev/curr: ${prevRate}/${currRate}`)
if (prevRate + currRate >= limit)
throw new RateLimitError(`Rate limit exceeded. Please try again later.`)
},
}
}
function buildYYYYMMDDHH(timestamp: number) {
return new Date(timestamp)
.toISOString()
.replace(/[^0-9]/g, "")
.substring(0, 10)
}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../../sst-env.d.ts" /> /// <reference path="../../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -7,7 +7,6 @@ import { ZenData } from "../src/model"
const root = path.resolve(process.cwd(), "..", "..", "..") const root = path.resolve(process.cwd(), "..", "..", "..")
const models = await $`bun sst secret list`.cwd(root).text() const models = await $`bun sst secret list`.cwd(root).text()
console.log("models", models)
// read the line starting with "ZEN_MODELS" // read the line starting with "ZEN_MODELS"
const oldValue1 = models const oldValue1 = models

View File

@@ -24,6 +24,7 @@ export namespace ZenData {
cost: ModelCostSchema, cost: ModelCostSchema,
cost200K: ModelCostSchema.optional(), cost200K: ModelCostSchema.optional(),
allowAnonymous: z.boolean().optional(), allowAnonymous: z.boolean().optional(),
rateLimit: z.number().optional(),
providers: z.array( providers: z.array(
z.object({ z.object({
id: z.string(), id: z.string(),

View File

@@ -6,99 +6,108 @@
import "sst" import "sst"
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
ADMIN_SECRET: { "ADMIN_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AUTH_API_URL: { "AUTH_API_URL": {
type: "sst.sst.Linkable" "type": "sst.sst.Linkable"
value: string "value": string
} }
AWS_SES_ACCESS_KEY_ID: { "AWS_SES_ACCESS_KEY_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AWS_SES_SECRET_ACCESS_KEY: { "AWS_SES_SECRET_ACCESS_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
Console: { "CLOUDFLARE_API_TOKEN": {
type: "sst.cloudflare.SolidStart" "type": "sst.sst.Secret"
url: string "value": string
} }
Database: { "CLOUDFLARE_DEFAULT_ACCOUNT_ID": {
database: string "type": "sst.sst.Secret"
host: string "value": string
password: string
port: number
type: "sst.sst.Linkable"
username: string
} }
Desktop: { "Console": {
type: "sst.cloudflare.StaticSite" "type": "sst.cloudflare.SolidStart"
url: string "url": string
} }
EMAILOCTOPUS_API_KEY: { "Database": {
type: "sst.sst.Secret" "database": string
value: string "host": string
"password": string
"port": number
"type": "sst.sst.Linkable"
"username": string
} }
GITHUB_APP_ID: { "Desktop": {
type: "sst.sst.Secret" "type": "sst.cloudflare.StaticSite"
value: string "url": string
} }
GITHUB_APP_PRIVATE_KEY: { "EMAILOCTOPUS_API_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_ID_CONSOLE: { "GITHUB_APP_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_SECRET_CONSOLE: { "GITHUB_APP_PRIVATE_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GOOGLE_CLIENT_ID: { "GITHUB_CLIENT_ID_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
HONEYCOMB_API_KEY: { "GITHUB_CLIENT_SECRET_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
STRIPE_SECRET_KEY: { "GOOGLE_CLIENT_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
STRIPE_WEBHOOK_SECRET: { "HONEYCOMB_API_KEY": {
type: "sst.sst.Linkable" "type": "sst.sst.Secret"
value: string "value": string
} }
Web: { "STRIPE_SECRET_KEY": {
type: "sst.cloudflare.Astro" "type": "sst.sst.Secret"
url: string "value": string
} }
ZEN_MODELS1: { "STRIPE_WEBHOOK_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Linkable"
value: string "value": string
} }
ZEN_MODELS2: { "Web": {
type: "sst.sst.Secret" "type": "sst.cloudflare.Astro"
value: string "url": string
}
"ZEN_MODELS1": {
"type": "sst.sst.Secret"
"value": string
}
"ZEN_MODELS2": {
"type": "sst.sst.Secret"
"value": string
} }
} }
} }
// cloudflare // cloudflare
import * as cloudflare from "@cloudflare/workers-types" import * as cloudflare from "@cloudflare/workers-types";
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
Api: cloudflare.Service "Api": cloudflare.Service
AuthApi: cloudflare.Service "AuthApi": cloudflare.Service
AuthStorage: cloudflare.KVNamespace "AuthStorage": cloudflare.KVNamespace
Bucket: cloudflare.R2Bucket "Bucket": cloudflare.R2Bucket
LogProcessor: cloudflare.Service "GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
} }
} }
import "sst" import "sst"
export {} export {}

View File

@@ -6,99 +6,108 @@
import "sst" import "sst"
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
ADMIN_SECRET: { "ADMIN_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AUTH_API_URL: { "AUTH_API_URL": {
type: "sst.sst.Linkable" "type": "sst.sst.Linkable"
value: string "value": string
} }
AWS_SES_ACCESS_KEY_ID: { "AWS_SES_ACCESS_KEY_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AWS_SES_SECRET_ACCESS_KEY: { "AWS_SES_SECRET_ACCESS_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
Console: { "CLOUDFLARE_API_TOKEN": {
type: "sst.cloudflare.SolidStart" "type": "sst.sst.Secret"
url: string "value": string
} }
Database: { "CLOUDFLARE_DEFAULT_ACCOUNT_ID": {
database: string "type": "sst.sst.Secret"
host: string "value": string
password: string
port: number
type: "sst.sst.Linkable"
username: string
} }
Desktop: { "Console": {
type: "sst.cloudflare.StaticSite" "type": "sst.cloudflare.SolidStart"
url: string "url": string
} }
EMAILOCTOPUS_API_KEY: { "Database": {
type: "sst.sst.Secret" "database": string
value: string "host": string
"password": string
"port": number
"type": "sst.sst.Linkable"
"username": string
} }
GITHUB_APP_ID: { "Desktop": {
type: "sst.sst.Secret" "type": "sst.cloudflare.StaticSite"
value: string "url": string
} }
GITHUB_APP_PRIVATE_KEY: { "EMAILOCTOPUS_API_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_ID_CONSOLE: { "GITHUB_APP_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_SECRET_CONSOLE: { "GITHUB_APP_PRIVATE_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GOOGLE_CLIENT_ID: { "GITHUB_CLIENT_ID_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
HONEYCOMB_API_KEY: { "GITHUB_CLIENT_SECRET_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
STRIPE_SECRET_KEY: { "GOOGLE_CLIENT_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
STRIPE_WEBHOOK_SECRET: { "HONEYCOMB_API_KEY": {
type: "sst.sst.Linkable" "type": "sst.sst.Secret"
value: string "value": string
} }
Web: { "STRIPE_SECRET_KEY": {
type: "sst.cloudflare.Astro" "type": "sst.sst.Secret"
url: string "value": string
} }
ZEN_MODELS1: { "STRIPE_WEBHOOK_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Linkable"
value: string "value": string
} }
ZEN_MODELS2: { "Web": {
type: "sst.sst.Secret" "type": "sst.cloudflare.Astro"
value: string "url": string
}
"ZEN_MODELS1": {
"type": "sst.sst.Secret"
"value": string
}
"ZEN_MODELS2": {
"type": "sst.sst.Secret"
"value": string
} }
} }
} }
// cloudflare // cloudflare
import * as cloudflare from "@cloudflare/workers-types" import * as cloudflare from "@cloudflare/workers-types";
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
Api: cloudflare.Service "Api": cloudflare.Service
AuthApi: cloudflare.Service "AuthApi": cloudflare.Service
AuthStorage: cloudflare.KVNamespace "AuthStorage": cloudflare.KVNamespace
Bucket: cloudflare.R2Bucket "Bucket": cloudflare.R2Bucket
LogProcessor: cloudflare.Service "GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
} }
} }
import "sst" import "sst"
export {} export {}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../../sst-env.d.ts" /> /// <reference path="../../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -13,6 +13,9 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@tsconfig/node22": "22.0.2" "@cloudflare/workers-types": "catalog:",
"@tsconfig/node22": "22.0.2",
"@types/node": "catalog:",
"cloudflare": "5.2.0"
} }
} }

View File

@@ -1 +1,64 @@
export { Resource } from "sst" import type {
KVNamespaceListOptions,
KVNamespaceListResult,
KVNamespacePutOptions,
} from "@cloudflare/workers-types"
import { Resource as ResourceBase } from "sst"
import Cloudflare from "cloudflare"
export const Resource = new Proxy(
{},
{
get(_target, prop: keyof typeof ResourceBase) {
const value = ResourceBase[prop]
// @ts-ignore
if ("type" in value && value.type === "sst.cloudflare.Kv") {
const client = new Cloudflare({
apiToken: ResourceBase.CLOUDFLARE_API_TOKEN.value,
})
// @ts-ignore
const namespaceId = value.namespaceId
const accountId = ResourceBase.CLOUDFLARE_DEFAULT_ACCOUNT_ID.value
return {
get: (k: string | string[]) => {
const isMulti = Array.isArray(k)
return client.kv.namespaces
.bulkGet(namespaceId, {
keys: Array.isArray(k) ? k : [k],
account_id: accountId,
})
.then((result) =>
isMulti ? new Map(Object.entries(result?.values ?? {})) : result?.values?.[k],
)
},
put: (k: string, v: string, opts?: KVNamespacePutOptions) =>
client.kv.namespaces.values.update(namespaceId, k, {
account_id: accountId,
value: v,
expiration: opts?.expiration,
expiration_ttl: opts?.expirationTtl,
metadata: opts?.metadata,
}),
delete: (k: string) =>
client.kv.namespaces.values.delete(namespaceId, k, {
account_id: accountId,
}),
list: (opts?: KVNamespaceListOptions): Promise<KVNamespaceListResult<unknown, string>> =>
client.kv.namespaces.keys
.list(namespaceId, {
account_id: accountId,
prefix: opts?.prefix ?? undefined,
})
.then((result) => {
return {
keys: result.result,
list_complete: true,
cacheStatus: null,
}
}),
}
}
return value
},
},
) as Record<string, any>

View File

@@ -6,99 +6,108 @@
import "sst" import "sst"
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
ADMIN_SECRET: { "ADMIN_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AUTH_API_URL: { "AUTH_API_URL": {
type: "sst.sst.Linkable" "type": "sst.sst.Linkable"
value: string "value": string
} }
AWS_SES_ACCESS_KEY_ID: { "AWS_SES_ACCESS_KEY_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AWS_SES_SECRET_ACCESS_KEY: { "AWS_SES_SECRET_ACCESS_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
Console: { "CLOUDFLARE_API_TOKEN": {
type: "sst.cloudflare.SolidStart" "type": "sst.sst.Secret"
url: string "value": string
} }
Database: { "CLOUDFLARE_DEFAULT_ACCOUNT_ID": {
database: string "type": "sst.sst.Secret"
host: string "value": string
password: string
port: number
type: "sst.sst.Linkable"
username: string
} }
Desktop: { "Console": {
type: "sst.cloudflare.StaticSite" "type": "sst.cloudflare.SolidStart"
url: string "url": string
} }
EMAILOCTOPUS_API_KEY: { "Database": {
type: "sst.sst.Secret" "database": string
value: string "host": string
"password": string
"port": number
"type": "sst.sst.Linkable"
"username": string
} }
GITHUB_APP_ID: { "Desktop": {
type: "sst.sst.Secret" "type": "sst.cloudflare.StaticSite"
value: string "url": string
} }
GITHUB_APP_PRIVATE_KEY: { "EMAILOCTOPUS_API_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_ID_CONSOLE: { "GITHUB_APP_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_SECRET_CONSOLE: { "GITHUB_APP_PRIVATE_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GOOGLE_CLIENT_ID: { "GITHUB_CLIENT_ID_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
HONEYCOMB_API_KEY: { "GITHUB_CLIENT_SECRET_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
STRIPE_SECRET_KEY: { "GOOGLE_CLIENT_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
STRIPE_WEBHOOK_SECRET: { "HONEYCOMB_API_KEY": {
type: "sst.sst.Linkable" "type": "sst.sst.Secret"
value: string "value": string
} }
Web: { "STRIPE_SECRET_KEY": {
type: "sst.cloudflare.Astro" "type": "sst.sst.Secret"
url: string "value": string
} }
ZEN_MODELS1: { "STRIPE_WEBHOOK_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Linkable"
value: string "value": string
} }
ZEN_MODELS2: { "Web": {
type: "sst.sst.Secret" "type": "sst.cloudflare.Astro"
value: string "url": string
}
"ZEN_MODELS1": {
"type": "sst.sst.Secret"
"value": string
}
"ZEN_MODELS2": {
"type": "sst.sst.Secret"
"value": string
} }
} }
} }
// cloudflare // cloudflare
import * as cloudflare from "@cloudflare/workers-types" import * as cloudflare from "@cloudflare/workers-types";
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
Api: cloudflare.Service "Api": cloudflare.Service
AuthApi: cloudflare.Service "AuthApi": cloudflare.Service
AuthStorage: cloudflare.KVNamespace "AuthStorage": cloudflare.KVNamespace
Bucket: cloudflare.R2Bucket "Bucket": cloudflare.R2Bucket
LogProcessor: cloudflare.Service "GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
} }
} }
import "sst" import "sst"
export {} export {}

View File

@@ -2,7 +2,9 @@
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
/// <reference types="vite/client" /> /// <reference types="vite/client" />
interface ImportMetaEnv {} interface ImportMetaEnv {
}
interface ImportMeta { interface ImportMeta {
readonly env: ImportMetaEnv readonly env: ImportMetaEnv
} }

View File

@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" /> /// <reference path="../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -6,99 +6,108 @@
import "sst" import "sst"
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
ADMIN_SECRET: { "ADMIN_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AUTH_API_URL: { "AUTH_API_URL": {
type: "sst.sst.Linkable" "type": "sst.sst.Linkable"
value: string "value": string
} }
AWS_SES_ACCESS_KEY_ID: { "AWS_SES_ACCESS_KEY_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AWS_SES_SECRET_ACCESS_KEY: { "AWS_SES_SECRET_ACCESS_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
Console: { "CLOUDFLARE_API_TOKEN": {
type: "sst.cloudflare.SolidStart" "type": "sst.sst.Secret"
url: string "value": string
} }
Database: { "CLOUDFLARE_DEFAULT_ACCOUNT_ID": {
database: string "type": "sst.sst.Secret"
host: string "value": string
password: string
port: number
type: "sst.sst.Linkable"
username: string
} }
Desktop: { "Console": {
type: "sst.cloudflare.StaticSite" "type": "sst.cloudflare.SolidStart"
url: string "url": string
} }
EMAILOCTOPUS_API_KEY: { "Database": {
type: "sst.sst.Secret" "database": string
value: string "host": string
"password": string
"port": number
"type": "sst.sst.Linkable"
"username": string
} }
GITHUB_APP_ID: { "Desktop": {
type: "sst.sst.Secret" "type": "sst.cloudflare.StaticSite"
value: string "url": string
} }
GITHUB_APP_PRIVATE_KEY: { "EMAILOCTOPUS_API_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_ID_CONSOLE: { "GITHUB_APP_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_SECRET_CONSOLE: { "GITHUB_APP_PRIVATE_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GOOGLE_CLIENT_ID: { "GITHUB_CLIENT_ID_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
HONEYCOMB_API_KEY: { "GITHUB_CLIENT_SECRET_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
STRIPE_SECRET_KEY: { "GOOGLE_CLIENT_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
STRIPE_WEBHOOK_SECRET: { "HONEYCOMB_API_KEY": {
type: "sst.sst.Linkable" "type": "sst.sst.Secret"
value: string "value": string
} }
Web: { "STRIPE_SECRET_KEY": {
type: "sst.cloudflare.Astro" "type": "sst.sst.Secret"
url: string "value": string
} }
ZEN_MODELS1: { "STRIPE_WEBHOOK_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Linkable"
value: string "value": string
} }
ZEN_MODELS2: { "Web": {
type: "sst.sst.Secret" "type": "sst.cloudflare.Astro"
value: string "url": string
}
"ZEN_MODELS1": {
"type": "sst.sst.Secret"
"value": string
}
"ZEN_MODELS2": {
"type": "sst.sst.Secret"
"value": string
} }
} }
} }
// cloudflare // cloudflare
import * as cloudflare from "@cloudflare/workers-types" import * as cloudflare from "@cloudflare/workers-types";
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
Api: cloudflare.Service "Api": cloudflare.Service
AuthApi: cloudflare.Service "AuthApi": cloudflare.Service
AuthStorage: cloudflare.KVNamespace "AuthStorage": cloudflare.KVNamespace
Bucket: cloudflare.R2Bucket "Bucket": cloudflare.R2Bucket
LogProcessor: cloudflare.Service "GatewayKv": cloudflare.KVNamespace
"LogProcessor": cloudflare.Service
} }
} }
import "sst" import "sst"
export {} export {}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" /> /// <reference path="../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" /> /// <reference path="../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" /> /// <reference path="../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../../sst-env.d.ts" /> /// <reference path="../../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -25,10 +25,17 @@ class Resource:
type: str type: str
url: str url: str
class AuthStorage: class AuthStorage:
namespaceId: str
type: str type: str
class Bucket: class Bucket:
name: str name: str
type: str type: str
class CLOUDFLARE_API_TOKEN:
type: str
value: str
class CLOUDFLARE_DEFAULT_ACCOUNT_ID:
type: str
value: str
class Console: class Console:
type: str type: str
url: str url: str
@@ -60,6 +67,9 @@ class Resource:
class GOOGLE_CLIENT_ID: class GOOGLE_CLIENT_ID:
type: str type: str
value: str value: str
class GatewayKv:
namespaceId: str
type: str
class HONEYCOMB_API_KEY: class HONEYCOMB_API_KEY:
type: str type: str
value: str value: str

View File

@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" /> /// <reference path="../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" /> /// <reference path="../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" /> /// <reference path="../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

View File

@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" /> /// <reference path="../../sst-env.d.ts" />
import "sst" import "sst"
export {} export {}

163
sst-env.d.ts vendored
View File

@@ -5,107 +5,120 @@
declare module "sst" { declare module "sst" {
export interface Resource { export interface Resource {
ADMIN_SECRET: { "ADMIN_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AUTH_API_URL: { "AUTH_API_URL": {
type: "sst.sst.Linkable" "type": "sst.sst.Linkable"
value: string "value": string
} }
AWS_SES_ACCESS_KEY_ID: { "AWS_SES_ACCESS_KEY_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
AWS_SES_SECRET_ACCESS_KEY: { "AWS_SES_SECRET_ACCESS_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
Api: { "Api": {
type: "sst.cloudflare.Worker" "type": "sst.cloudflare.Worker"
url: string "url": string
} }
AuthApi: { "AuthApi": {
type: "sst.cloudflare.Worker" "type": "sst.cloudflare.Worker"
url: string "url": string
} }
AuthStorage: { "AuthStorage": {
type: "sst.cloudflare.Kv" "namespaceId": string
"type": "sst.cloudflare.Kv"
} }
Bucket: { "Bucket": {
name: string "name": string
type: "sst.cloudflare.Bucket" "type": "sst.cloudflare.Bucket"
} }
Console: { "CLOUDFLARE_API_TOKEN": {
type: "sst.cloudflare.SolidStart" "type": "sst.sst.Secret"
url: string "value": string
} }
Database: { "CLOUDFLARE_DEFAULT_ACCOUNT_ID": {
database: string "type": "sst.sst.Secret"
host: string "value": string
password: string
port: number
type: "sst.sst.Linkable"
username: string
} }
Desktop: { "Console": {
type: "sst.cloudflare.StaticSite" "type": "sst.cloudflare.SolidStart"
url: string "url": string
} }
EMAILOCTOPUS_API_KEY: { "Database": {
type: "sst.sst.Secret" "database": string
value: string "host": string
"password": string
"port": number
"type": "sst.sst.Linkable"
"username": string
} }
GITHUB_APP_ID: { "Desktop": {
type: "sst.sst.Secret" "type": "sst.cloudflare.StaticSite"
value: string "url": string
} }
GITHUB_APP_PRIVATE_KEY: { "EMAILOCTOPUS_API_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_ID_CONSOLE: { "GITHUB_APP_ID": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GITHUB_CLIENT_SECRET_CONSOLE: { "GITHUB_APP_PRIVATE_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
GOOGLE_CLIENT_ID: { "GITHUB_CLIENT_ID_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
HONEYCOMB_API_KEY: { "GITHUB_CLIENT_SECRET_CONSOLE": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
LogProcessor: { "GOOGLE_CLIENT_ID": {
type: "sst.cloudflare.Worker" "type": "sst.sst.Secret"
"value": string
} }
STRIPE_SECRET_KEY: { "GatewayKv": {
type: "sst.sst.Secret" "namespaceId": string
value: string "type": "sst.cloudflare.Kv"
} }
STRIPE_WEBHOOK_SECRET: { "HONEYCOMB_API_KEY": {
type: "sst.sst.Linkable" "type": "sst.sst.Secret"
value: string "value": string
} }
Web: { "LogProcessor": {
type: "sst.cloudflare.Astro" "type": "sst.cloudflare.Worker"
url: string
} }
ZEN_MODELS1: { "STRIPE_SECRET_KEY": {
type: "sst.sst.Secret" "type": "sst.sst.Secret"
value: string "value": string
} }
ZEN_MODELS2: { "STRIPE_WEBHOOK_SECRET": {
type: "sst.sst.Secret" "type": "sst.sst.Linkable"
value: string "value": string
}
"Web": {
"type": "sst.cloudflare.Astro"
"url": string
}
"ZEN_MODELS1": {
"type": "sst.sst.Secret"
"value": string
}
"ZEN_MODELS2": {
"type": "sst.sst.Secret"
"value": string
} }
} }
} }
/// <reference path="sst-env.d.ts" /> /// <reference path="sst-env.d.ts" />
import "sst" import "sst"
export {} export {}