You've already forked AstralRinth
forked from didirus/AstralRinth
Worker migration (#5072)
* Worker migration * Deploy on pnpm changes * Specify package manager * Manually bump Wrangler to 4.54 * Get rid of useless Wranglers worker * I take it back * Set account ID * Fix preview alias * feat: use workers api key * feat: try fix * fix: missing imports * fix: again * fix: only run push workflow on main or prod * feat: remove store id? * Populate secret store IDs * Use correct key name * Fix setting PREVIEW variable * Inject variables from wrangler into shell * Inject variables from wrangler into shell * Add git- prefix to preview-alias * No need to use environments now * fix: remove test as it's covered by staging deploy --------- Co-authored-by: Michael H. <michael@iptables.sh>
This commit is contained in:
98
.github/workflows/frontend-deploy.yml
vendored
Normal file
98
.github/workflows/frontend-deploy.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
name: Deploy frontend
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- prod
|
||||||
|
paths:
|
||||||
|
- 'apps/frontend/**/*'
|
||||||
|
- 'packages/ui/**/*'
|
||||||
|
- 'packages/utils/**/*'
|
||||||
|
- 'packages/assets/**/*'
|
||||||
|
- '**/wrangler.jsonc'
|
||||||
|
- '**/pnpm-*.yaml'
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
if: github.repository_owner == 'modrinth'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
deployments: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Configure environment
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
echo "cmd=deploy" >> $GITHUB_OUTPUT
|
||||||
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
||||||
|
echo "env=staging" >> $GITHUB_OUTPUT
|
||||||
|
echo "url=https://staging.modrinth.com" >> $GITHUB_OUTPUT
|
||||||
|
elif [ "${{ github.ref }}" != "refs/heads/prod" ] && [ "${{ github.ref }}" != "refs/heads/main" ]; then
|
||||||
|
echo "env=staging" >> $GITHUB_OUTPUT
|
||||||
|
echo "url=https://git-${GITHUB_SHA::8}-frontend-staging.modrinth.workers.dev" >> $GITHUB_OUTPUT
|
||||||
|
echo "cmd=versions upload --preview-alias git-${GITHUB_SHA::8} --var PREVIEW:true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
# Production env should be empty
|
||||||
|
echo "url=https://modrinth.com" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .nvmrc
|
||||||
|
cache: pnpm
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: ./apps/frontend
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Inject build variables
|
||||||
|
working-directory: ./apps/frontend
|
||||||
|
run: |
|
||||||
|
if [ "${{ steps.meta.outputs.env }}" == "staging" ]; then
|
||||||
|
echo "Injecting staging variables from wrangler.jsonc..."
|
||||||
|
jq -r '.env.staging.vars | to_entries[] | "export \(.key)=\(.value|@sh)"' wrangler.jsonc | source /dev/stdin
|
||||||
|
else
|
||||||
|
echo "Injecting production variables from wrangler.jsonc..."
|
||||||
|
jq -r '.vars | to_entries[] | "export \(.key)=\(.value|@sh)"' wrangler.jsonc | source /dev/stdin
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build frontend
|
||||||
|
working-directory: ./apps/frontend
|
||||||
|
run: pnpm build
|
||||||
|
env:
|
||||||
|
CF_PAGES_BRANCH: ${{ github.ref_name }}
|
||||||
|
CF_PAGES_COMMIT_SHA: ${{ github.sha }}
|
||||||
|
CF_PAGES_URL: ${{ steps.meta.outputs.url }}
|
||||||
|
|
||||||
|
- name: Deploy Cloudflare Worker
|
||||||
|
id: wrangler
|
||||||
|
uses: cloudflare/wrangler-action@v3
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
||||||
|
environment: ${{ steps.meta.outputs.env }}
|
||||||
|
workingDirectory: ./apps/frontend
|
||||||
|
packageManager: pnpm
|
||||||
|
wranglerVersion: '4.54.0'
|
||||||
|
command: ${{ steps.meta.outputs.cmd }}
|
||||||
|
|
||||||
|
- name: Purge cache
|
||||||
|
if: github.ref == 'refs/heads/prod'
|
||||||
|
run: |
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: Bearer ${{ secrets.CF_API_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
--data '{"hosts": ["modrinth.com", "www.modrinth.com", "staging.modrinth.com"]}' \
|
||||||
|
https://api.cloudflare.com/client/v4/zones/e39df17b9c4ef44cbce2646346ee6d33/purge_cache
|
||||||
30
.github/workflows/frontend-pages.yml
vendored
30
.github/workflows/frontend-pages.yml
vendored
@@ -1,30 +0,0 @@
|
|||||||
name: Clear pages cache
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- prod
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
wait:
|
|
||||||
if: github.repository_owner == 'modrinth'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
deployments: write
|
|
||||||
steps:
|
|
||||||
- name: Cloudflare Pages deployment
|
|
||||||
uses: WalshyDev/cf-pages-await@v1
|
|
||||||
with:
|
|
||||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
|
||||||
accountId: '9ddae624c98677d68d93df6e524a6061'
|
|
||||||
project: 'frontend'
|
|
||||||
commitHash: ${{ steps.push-changes.outputs.commit-hash }}
|
|
||||||
- name: Purge cache
|
|
||||||
if: github.ref == 'refs/heads/prod'
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Authorization: Bearer ${{ secrets.CF_API_TOKEN }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
--data '{"hosts": ["modrinth.com", "www.modrinth.com"]}' \
|
|
||||||
https://api.cloudflare.com/client/v4/zones/e39df17b9c4ef44cbce2646346ee6d33/purge_cache
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import { GenericModrinthClient, type Labrinth } from '@modrinth/api-client'
|
import { GenericModrinthClient, type Labrinth } from '@modrinth/api-client'
|
||||||
// Import directly from utils to avoid loading .vue files at config time
|
|
||||||
import { LOCALES } from '@modrinth/ui/src/composables/i18n.ts'
|
import { LOCALES } from '@modrinth/ui/src/composables/i18n.ts'
|
||||||
import serverSidedVue from '@vitejs/plugin-vue'
|
import serverSidedVue from '@vitejs/plugin-vue'
|
||||||
import { promises as fs } from 'fs'
|
import fs from 'fs/promises'
|
||||||
import { defineNuxtConfig } from 'nuxt/config'
|
import { defineNuxtConfig } from 'nuxt/config'
|
||||||
import svgLoader from 'vite-svg-loader'
|
import svgLoader from 'vite-svg-loader'
|
||||||
|
|
||||||
@@ -96,6 +95,11 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
external: ['cloudflare:workers'],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
hooks: {
|
hooks: {
|
||||||
async 'nitro:config'(nitroConfig) {
|
async 'nitro:config'(nitroConfig) {
|
||||||
@@ -183,7 +187,7 @@ export default defineNuxtConfig({
|
|||||||
process.env.CF_PAGES_BRANCH ||
|
process.env.CF_PAGES_BRANCH ||
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
globalThis.CF_PAGES_BRANCH ||
|
globalThis.CF_PAGES_BRANCH ||
|
||||||
'master',
|
'main',
|
||||||
hash:
|
hash:
|
||||||
process.env.VERCEL_GIT_COMMIT_SHA ||
|
process.env.VERCEL_GIT_COMMIT_SHA ||
|
||||||
process.env.CF_PAGES_COMMIT_SHA ||
|
process.env.CF_PAGES_COMMIT_SHA ||
|
||||||
@@ -246,6 +250,11 @@ export default defineNuxtConfig({
|
|||||||
rollupConfig: {
|
rollupConfig: {
|
||||||
// @ts-expect-error because of rolldown-vite - completely fine though
|
// @ts-expect-error because of rolldown-vite - completely fine though
|
||||||
plugins: [serverSidedVue()],
|
plugins: [serverSidedVue()],
|
||||||
|
external: ['cloudflare:workers'],
|
||||||
|
},
|
||||||
|
preset: 'cloudflare_module',
|
||||||
|
cloudflare: {
|
||||||
|
nodeCompat: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
devtools: {
|
devtools: {
|
||||||
@@ -308,11 +317,8 @@ function getFeatureFlagOverrides() {
|
|||||||
|
|
||||||
function getDomain() {
|
function getDomain() {
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
if (process.env.SITE_URL) {
|
|
||||||
return process.env.SITE_URL
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
else if (process.env.CF_PAGES_URL || globalThis.CF_PAGES_URL) {
|
if (process.env.CF_PAGES_URL || globalThis.CF_PAGES_URL) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return process.env.CF_PAGES_URL ?? globalThis.CF_PAGES_URL
|
return process.env.CF_PAGES_URL ?? globalThis.CF_PAGES_URL
|
||||||
} else if (process.env.HEROKU_APP_NAME) {
|
} else if (process.env.HEROKU_APP_NAME) {
|
||||||
|
|||||||
@@ -11,7 +11,9 @@
|
|||||||
"lint": "eslint . && prettier --check .",
|
"lint": "eslint . && prettier --check .",
|
||||||
"fix": "eslint . --fix && prettier --write .",
|
"fix": "eslint . --fix && prettier --write .",
|
||||||
"intl:extract": "formatjs extract \"src/{components,composables,layouts,middleware,modules,pages,plugins,utils}/**/*.{vue,ts,tsx,js,jsx,mts,cts,mjs,cjs}\" \"src/error.vue\" --ignore \"**/*.d.ts\" --ignore node_modules --out-file src/locales/en-US/index.json --format crowdin --preserve-whitespace",
|
"intl:extract": "formatjs extract \"src/{components,composables,layouts,middleware,modules,pages,plugins,utils}/**/*.{vue,ts,tsx,js,jsx,mts,cts,mjs,cjs}\" \"src/error.vue\" --ignore \"**/*.d.ts\" --ignore node_modules --out-file src/locales/en-US/index.json --format crowdin --preserve-whitespace",
|
||||||
"test": "pnpm build"
|
"cf-deploy": "pnpm run build && wrangler deploy --env preview",
|
||||||
|
"cf-dev": "pnpm run build && wrangler dev --env preview",
|
||||||
|
"cf-typegen": "wrangler types"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@formatjs/cli": "^6.2.12",
|
"@formatjs/cli": "^6.2.12",
|
||||||
@@ -30,7 +32,8 @@
|
|||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"vite-svg-loader": "^5.1.0",
|
"vite-svg-loader": "^5.1.0",
|
||||||
"vue-component-type-helpers": "^3.1.8",
|
"vue-component-type-helpers": "^3.1.8",
|
||||||
"vue-tsc": "^2.0.24"
|
"vue-tsc": "^2.0.24",
|
||||||
|
"wrangler": "^4.54.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formatjs/intl-localematcher": "^0.5.4",
|
"@formatjs/intl-localematcher": "^0.5.4",
|
||||||
|
|||||||
@@ -1,3 +1,25 @@
|
|||||||
|
let cachedRateLimitKey = undefined
|
||||||
|
let rateLimitKeyPromise = undefined
|
||||||
|
|
||||||
|
async function getRateLimitKey(config) {
|
||||||
|
if (config.rateLimitKey) return config.rateLimitKey
|
||||||
|
if (cachedRateLimitKey !== undefined) return cachedRateLimitKey
|
||||||
|
|
||||||
|
if (!rateLimitKeyPromise) {
|
||||||
|
rateLimitKeyPromise = (async () => {
|
||||||
|
try {
|
||||||
|
const { env } = await import('cloudflare:workers')
|
||||||
|
return await env.RATE_LIMIT_IGNORE_KEY?.get()
|
||||||
|
} catch {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedRateLimitKey = await rateLimitKeyPromise
|
||||||
|
return cachedRateLimitKey
|
||||||
|
}
|
||||||
|
|
||||||
export const useBaseFetch = async (url, options = {}, skipAuth = false) => {
|
export const useBaseFetch = async (url, options = {}, skipAuth = false) => {
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
let base = import.meta.server ? config.apiBaseUrl : config.public.apiBaseUrl
|
let base = import.meta.server ? config.apiBaseUrl : config.public.apiBaseUrl
|
||||||
@@ -7,7 +29,7 @@ export const useBaseFetch = async (url, options = {}, skipAuth = false) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (import.meta.server) {
|
if (import.meta.server) {
|
||||||
options.headers['x-ratelimit-key'] = config.rateLimitKey
|
options.headers['x-ratelimit-key'] = await getRateLimitKey(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipAuth) {
|
if (!skipAuth) {
|
||||||
|
|||||||
@@ -13,6 +13,17 @@ import {
|
|||||||
} from '@modrinth/api-client'
|
} from '@modrinth/api-client'
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
|
|
||||||
|
async function getRateLimitKeyFromSecretsStore(): Promise<string | undefined> {
|
||||||
|
try {
|
||||||
|
// @ts-expect-error only avail in workers env
|
||||||
|
const { env } = await import('cloudflare:workers')
|
||||||
|
return await env.RATE_LIMIT_IGNORE_KEY?.get()
|
||||||
|
} catch {
|
||||||
|
// Not running in Cloudflare Workers environment
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function createModrinthClient(
|
export function createModrinthClient(
|
||||||
auth: Ref<{ token: string | undefined }>,
|
auth: Ref<{ token: string | undefined }>,
|
||||||
config: { apiBaseUrl: string; archonBaseUrl: string; rateLimitKey?: string },
|
config: { apiBaseUrl: string; archonBaseUrl: string; rateLimitKey?: string },
|
||||||
@@ -24,7 +35,7 @@ export function createModrinthClient(
|
|||||||
const clientConfig: NuxtClientConfig = {
|
const clientConfig: NuxtClientConfig = {
|
||||||
labrinthBaseUrl: config.apiBaseUrl,
|
labrinthBaseUrl: config.apiBaseUrl,
|
||||||
archonBaseUrl: config.archonBaseUrl,
|
archonBaseUrl: config.archonBaseUrl,
|
||||||
rateLimitKey: config.rateLimitKey,
|
rateLimitKey: config.rateLimitKey || getRateLimitKeyFromSecretsStore,
|
||||||
features: [
|
features: [
|
||||||
// for modrinth hosting
|
// for modrinth hosting
|
||||||
// is skipped for normal reqs
|
// is skipped for normal reqs
|
||||||
|
|||||||
59
apps/frontend/wrangler.jsonc
Normal file
59
apps/frontend/wrangler.jsonc
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"$schema": "node_modules/wrangler/config-schema.json",
|
||||||
|
"name": "frontend",
|
||||||
|
"compatibility_date": "2025-12-10",
|
||||||
|
"main": "./.output/server/index.mjs",
|
||||||
|
"assets": {
|
||||||
|
"binding": "ASSETS",
|
||||||
|
"directory": "./.output/public/"
|
||||||
|
},
|
||||||
|
"compatibility_flags": ["nodejs_compat", "no_nodejs_compat_v2"],
|
||||||
|
"preview_urls": true,
|
||||||
|
"workers_dev": true,
|
||||||
|
"limits": {
|
||||||
|
"cpu_ms": 2000
|
||||||
|
},
|
||||||
|
"observability": {
|
||||||
|
"enabled": true,
|
||||||
|
"head_sampling_rate": 0.001
|
||||||
|
},
|
||||||
|
"keep_vars": false,
|
||||||
|
"secrets_store_secrets": [
|
||||||
|
{
|
||||||
|
"binding": "RATE_LIMIT_IGNORE_KEY",
|
||||||
|
"store_id": "c9024fef252d4a53adf513feca64417d",
|
||||||
|
"secret_name": "labrinth-production-ratelimit-key"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vars": {
|
||||||
|
"ENVIRONMENT": "production",
|
||||||
|
"BASE_URL": "https://api.modrinth.com/v2/",
|
||||||
|
"BROWSER_BASE_URL": "https://api.modrinth.com/v2/",
|
||||||
|
"PYRO_BASE_URL": "https://archon.modrinth.com/",
|
||||||
|
"STRIPE_PUBLISHABLE_KEY": "pk_live_51JbFxJJygY5LJFfKLVVldb10HlLt24p421OWRsTOWc5sXYFOnFUXWieSc6HD3PHo25ktx8db1WcHr36XGFvZFVUz00V9ixrCs5"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"staging": {
|
||||||
|
"observability": {
|
||||||
|
"enabled": true,
|
||||||
|
"head_sampling_rate": 0.1
|
||||||
|
},
|
||||||
|
"routes": ["staging.modrinth.com/*"],
|
||||||
|
"vars": {
|
||||||
|
"ENVIRONMENT": "staging",
|
||||||
|
"BASE_URL": "https://staging-api.modrinth.com/v2/",
|
||||||
|
"BROWSER_BASE_URL": "https://staging-api.modrinth.com/v2/",
|
||||||
|
"PYRO_BASE_URL": "https://staging-archon.modrinth.com/",
|
||||||
|
"STRIPE_PUBLISHABLE_KEY": "pk_test_51JbFxJJygY5LJFfKV50mnXzz3YLvBVe2Gd1jn7ljWAkaBlRz3VQdxN9mXcPSrFbSqxwAb0svte9yhnsmm7qHfcWn00R611Ce7b"
|
||||||
|
},
|
||||||
|
"secrets_store_secrets": [
|
||||||
|
{
|
||||||
|
"binding": "RATE_LIMIT_IGNORE_KEY",
|
||||||
|
"store_id": "c9024fef252d4a53adf513feca64417d",
|
||||||
|
"secret_name": "labrinth-staging-ratelimit-key"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preview_urls": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,10 +43,11 @@ export class NuxtCircuitBreakerStorage implements CircuitBreakerStorage {
|
|||||||
export interface NuxtClientConfig extends ClientConfig {
|
export interface NuxtClientConfig extends ClientConfig {
|
||||||
// TODO: do we want to provide this for tauri+base as well? its not used on app
|
// TODO: do we want to provide this for tauri+base as well? its not used on app
|
||||||
/**
|
/**
|
||||||
* Rate limit key for server-side requests
|
* Rate limit key for server-side requests.
|
||||||
* This is injected as x-ratelimit-key header on server-side
|
* This is injected as x-ratelimit-key header on server-side.
|
||||||
|
* Can be a string (for env var) or async function (for CF Secrets Store).
|
||||||
*/
|
*/
|
||||||
rateLimitKey?: string
|
rateLimitKey?: string | (() => Promise<string | undefined>)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,6 +76,8 @@ export interface NuxtClientConfig extends ClientConfig {
|
|||||||
*/
|
*/
|
||||||
export class NuxtModrinthClient extends XHRUploadClient {
|
export class NuxtModrinthClient extends XHRUploadClient {
|
||||||
declare protected config: NuxtClientConfig
|
declare protected config: NuxtClientConfig
|
||||||
|
private rateLimitKeyResolved: string | undefined
|
||||||
|
private rateLimitKeyPromise: Promise<string | undefined> | undefined
|
||||||
|
|
||||||
constructor(config: NuxtClientConfig) {
|
constructor(config: NuxtClientConfig) {
|
||||||
super(config)
|
super(config)
|
||||||
@@ -87,6 +90,40 @@ export class NuxtModrinthClient extends XHRUploadClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the rate limit key, handling both string and async function values.
|
||||||
|
* Results are cached for subsequent calls.
|
||||||
|
*/
|
||||||
|
private async resolveRateLimitKey(): Promise<string | undefined> {
|
||||||
|
if (this.rateLimitKeyResolved !== undefined) {
|
||||||
|
return this.rateLimitKeyResolved
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = this.config.rateLimitKey
|
||||||
|
if (typeof key === 'string') {
|
||||||
|
this.rateLimitKeyResolved = key
|
||||||
|
} else if (typeof key === 'function') {
|
||||||
|
if (!this.rateLimitKeyPromise) {
|
||||||
|
this.rateLimitKeyPromise = key()
|
||||||
|
}
|
||||||
|
this.rateLimitKeyResolved = await this.rateLimitKeyPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.rateLimitKeyResolved
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override request to resolve rate limit key before calling super.
|
||||||
|
* This allows async fetching of the key from CF Secrets Store.
|
||||||
|
*/
|
||||||
|
async request<T>(path: string, options: RequestOptions): Promise<T> {
|
||||||
|
// @ts-expect-error - import.meta is provided by Nuxt
|
||||||
|
if (import.meta.server) {
|
||||||
|
await this.resolveRateLimitKey()
|
||||||
|
}
|
||||||
|
return super.request(path, options)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload a file with progress tracking
|
* Upload a file with progress tracking
|
||||||
*
|
*
|
||||||
@@ -132,9 +169,10 @@ export class NuxtModrinthClient extends XHRUploadClient {
|
|||||||
...super.buildDefaultHeaders(),
|
...super.buildDefaultHeaders(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the resolved key (populated by resolveRateLimitKey in request())
|
||||||
// @ts-expect-error - import.meta is provided by Nuxt
|
// @ts-expect-error - import.meta is provided by Nuxt
|
||||||
if (import.meta.server && this.config.rateLimitKey) {
|
if (import.meta.server && this.rateLimitKeyResolved) {
|
||||||
headers['x-ratelimit-key'] = this.config.rateLimitKey
|
headers['x-ratelimit-key'] = this.rateLimitKeyResolved
|
||||||
}
|
}
|
||||||
|
|
||||||
return headers
|
return headers
|
||||||
|
|||||||
487
pnpm-lock.yaml
generated
487
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user