@@ -508,11 +510,7 @@
{{ formatMessage(messages.upgrade) }}
-
@@ -95,17 +106,27 @@
:description="formatMessage(messages.emptyDescription)"
>
-
+
+
+
+
(() => [
const client = injectModrinthClient()
const queryClient = useQueryClient()
const { server, worldId, busyReasons } = injectModrinthServerContext()
+const { downloadWorldFiles } = useServerWorldDownload()
+const isDownloadingFiles = ref(false)
+
+async function downloadFiles() {
+ const node = server.value.node
+ const currentWorldId = worldId.value
+ if (!node || !currentWorldId || isDownloadingFiles.value) return
+
+ isDownloadingFiles.value = true
+ try {
+ await downloadWorldFiles(node.instance, currentWorldId)
+ } finally {
+ isDownloadingFiles.value = false
+ }
+}
const props = defineProps<{
isServerRunning: boolean
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/index.vue b/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
index 061d7c2e1c..ba1891ca23 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
@@ -188,7 +188,7 @@
:cancellation-date="serverBillingMap.get(server.server_id)?.cancellationDate"
:is-provisioning="serverBillingMap.get(server.server_id)?.isProvisioning"
:on-resubscribe="serverBillingMap.get(server.server_id)?.onResubscribe"
- :on-download-backup="serverBillingMap.get(server.server_id)?.onDownloadBackup"
+ :on-download-world="getWorldDownload(server.server_id, serverFullList)"
/>
@@ -238,16 +238,18 @@ import { HammerIcon, LoaderCircleIcon, PlusIcon, SearchIcon } from '@modrinth/as
import {
CopyCode,
defineMessages,
+ hasAvailableWorldDownload,
injectAuth,
injectModrinthClient,
injectNotificationManager,
Input,
IntlFormatted,
+ isWithinServerResubscribeWindow,
ModrinthServersPurchaseModal,
ResubscribeModal,
ServerListEmpty,
ServersGuestPlanModal,
- useServerBackupDownload,
+ useServerWorldDownload,
useVIntl,
} from '@modrinth/ui'
import { useQuery, useQueryClient } from '@tanstack/vue-query'
@@ -561,14 +563,14 @@ function sortServers(array: Archon.Servers.v0.Server[]): Archon.Servers.v0.Serve
})
}
-// files expire 30 days after cancellation
-function filesExpired(server: Archon.Servers.v0.Server): boolean {
- if (server.status !== 'suspended' || server.suspension_reason !== 'cancelled') return false
+function shouldShowServer(server: Archon.Servers.v0.Server): boolean {
+ if (server.status !== 'suspended' || server.suspension_reason !== 'cancelled') return true
const cancellationDate = serverBillingMap.value.get(server.server_id)?.cancellationDate
- if (!cancellationDate) return false
- const cancellation = new Date(cancellationDate)
- const thirtyDaysLater = new Date(cancellation.getTime() + 30 * 24 * 60 * 60 * 1000)
- return new Date() > thirtyDaysLater
+ if (!cancellationDate || !serverFullList.value) return true
+ return (
+ isWithinServerResubscribeWindow(cancellationDate) ||
+ hasAvailableWorldDownload(server.server_id, serverFullList.value)
+ )
}
function isServerOwnedByCurrentUser(server: Archon.Servers.v0.Server): boolean {
@@ -586,11 +588,13 @@ function getServerOwner(server: Archon.Servers.v0.Server): ServerListingOwner |
}
const ownedServerList = computed(() =>
- serverList.value.filter((server) => !filesExpired(server) && isServerOwnedByCurrentUser(server)),
+ serverList.value.filter(
+ (server) => shouldShowServer(server) && isServerOwnedByCurrentUser(server),
+ ),
)
const sharedServerList = computed(() =>
serverList.value
- .filter((server) => !filesExpired(server) && !isServerOwnedByCurrentUser(server))
+ .filter((server) => shouldShowServer(server) && !isServerOwnedByCurrentUser(server))
.map((server) => ({
...server,
owner: getServerOwner(server),
@@ -636,7 +640,7 @@ watch(serverResponse, (response) => {
const { addNotification } = injectNotificationManager()
const queryClient = useQueryClient()
-const { getLatestBackupDownload } = useServerBackupDownload()
+const { getWorldDownload } = useServerWorldDownload()
function handlePurchaseSuccess() {
startNewServerPolling(serverResponse.value?.servers ?? [])
@@ -776,7 +780,6 @@ type ServerBillingInfo = {
cancellationDate?: string | null
isProvisioning?: boolean
onResubscribe?: () => void
- onDownloadBackup?: (() => void) | null
}
type ResubscribeRequest = {
@@ -928,12 +931,12 @@ const serverBillingMap = computed(() => {
(charge?.status === 'processing' || charge?.status === 'open'),
}
- info.onDownloadBackup = getLatestBackupDownload(serverId, serverFullList.value)
-
if (charge?.status === 'cancelled') {
info.cancellationDate = charge.due
- info.onResubscribe = () => openResubscribeModal(serverId, sub, charge)
+ if (isWithinServerResubscribeWindow(charge.due)) {
+ info.onResubscribe = () => openResubscribeModal(serverId, sub, charge)
+ }
}
map.set(serverId, info)
diff --git a/packages/ui/src/locales/de-CH/index.json b/packages/ui/src/locales/de-CH/index.json
index 52c5297b3c..43507c9aff 100644
--- a/packages/ui/src/locales/de-CH/index.json
+++ b/packages/ui/src/locales/de-CH/index.json
@@ -5153,9 +5153,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "ID kopieren"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Neueste Sicherung herunterladen"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Abrechnung verwalten"
},
diff --git a/packages/ui/src/locales/de-DE/index.json b/packages/ui/src/locales/de-DE/index.json
index 63a10cf572..a69c6f5f49 100644
--- a/packages/ui/src/locales/de-DE/index.json
+++ b/packages/ui/src/locales/de-DE/index.json
@@ -5153,9 +5153,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "ID kopieren"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Neueste Sicherung herunterladen"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Abrechnung verwalten"
},
diff --git a/packages/ui/src/locales/en-US/index.json b/packages/ui/src/locales/en-US/index.json
index 363460f362..5207c916bf 100644
--- a/packages/ui/src/locales/en-US/index.json
+++ b/packages/ui/src/locales/en-US/index.json
@@ -206,6 +206,9 @@
"button.download": {
"defaultMessage": "Download"
},
+ "button.download-files": {
+ "defaultMessage": "Download files"
+ },
"button.downloading": {
"defaultMessage": "Downloading"
},
@@ -5162,6 +5165,18 @@
"servers.busy.installing": {
"defaultMessage": "Server is installing"
},
+ "servers.download.failed.description": {
+ "defaultMessage": "An error occurred while trying to download the world's files."
+ },
+ "servers.download.failed.title": {
+ "defaultMessage": "Download failed"
+ },
+ "servers.download.unavailable.description": {
+ "defaultMessage": "This world's files cannot currently be downloaded."
+ },
+ "servers.download.unavailable.title": {
+ "defaultMessage": "Download unavailable"
+ },
"servers.files.zip-created": {
"defaultMessage": "ZIP created"
},
@@ -5315,9 +5330,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Copy ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Download latest backup"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Manage billing"
},
diff --git a/packages/ui/src/locales/es-419/index.json b/packages/ui/src/locales/es-419/index.json
index 54d0d15df1..34b7cf5076 100644
--- a/packages/ui/src/locales/es-419/index.json
+++ b/packages/ui/src/locales/es-419/index.json
@@ -5153,9 +5153,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Copiar ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Descargar el respaldo más reciente"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Gestionar facturación"
},
diff --git a/packages/ui/src/locales/es-ES/index.json b/packages/ui/src/locales/es-ES/index.json
index 6d6cfc540a..21f3e22449 100644
--- a/packages/ui/src/locales/es-ES/index.json
+++ b/packages/ui/src/locales/es-ES/index.json
@@ -4952,9 +4952,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Copiar ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Descargar último respaldo"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Gestiona facturaciones"
},
diff --git a/packages/ui/src/locales/fr-FR/index.json b/packages/ui/src/locales/fr-FR/index.json
index 05ab48ec5d..abe70d6922 100644
--- a/packages/ui/src/locales/fr-FR/index.json
+++ b/packages/ui/src/locales/fr-FR/index.json
@@ -4832,9 +4832,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Copier l'ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Télécharger la dernière sauvegarde"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Gérer la facturation"
},
diff --git a/packages/ui/src/locales/hu-HU/index.json b/packages/ui/src/locales/hu-HU/index.json
index 991c9ab56e..8f063652ef 100644
--- a/packages/ui/src/locales/hu-HU/index.json
+++ b/packages/ui/src/locales/hu-HU/index.json
@@ -4175,9 +4175,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Azonosító másolása"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "A legfrissebb biztonsági mentés letöltése"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Számlázás kezelése"
},
diff --git a/packages/ui/src/locales/it-IT/index.json b/packages/ui/src/locales/it-IT/index.json
index aa9af79e61..85e8d69ebc 100644
--- a/packages/ui/src/locales/it-IT/index.json
+++ b/packages/ui/src/locales/it-IT/index.json
@@ -5096,9 +5096,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Copia ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Scarica l'ultimo backup"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Gestione fatturazione"
},
diff --git a/packages/ui/src/locales/ja-JP/index.json b/packages/ui/src/locales/ja-JP/index.json
index 5cd0e61468..801ba1f6ea 100644
--- a/packages/ui/src/locales/ja-JP/index.json
+++ b/packages/ui/src/locales/ja-JP/index.json
@@ -4487,9 +4487,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "IDをコピー"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "最新のバックアップをダウンロード"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "請求設定"
},
diff --git a/packages/ui/src/locales/ko-KR/index.json b/packages/ui/src/locales/ko-KR/index.json
index f7ad1e4ae6..440a78e538 100644
--- a/packages/ui/src/locales/ko-KR/index.json
+++ b/packages/ui/src/locales/ko-KR/index.json
@@ -4820,9 +4820,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "신분증 복사"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "최신 백업 다운로드"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "청구 관리"
},
diff --git a/packages/ui/src/locales/ms-MY/index.json b/packages/ui/src/locales/ms-MY/index.json
index 46b9247e74..afe5cd4d20 100644
--- a/packages/ui/src/locales/ms-MY/index.json
+++ b/packages/ui/src/locales/ms-MY/index.json
@@ -3905,9 +3905,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Salin ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Muat turun sandaran terkini"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Urus pengebilan"
},
diff --git a/packages/ui/src/locales/nl-NL/index.json b/packages/ui/src/locales/nl-NL/index.json
index b7ca9ce76b..03c5cc115a 100644
--- a/packages/ui/src/locales/nl-NL/index.json
+++ b/packages/ui/src/locales/nl-NL/index.json
@@ -4625,9 +4625,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Kopieer ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Laatste back-up downloaden"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Facturering beheren"
},
diff --git a/packages/ui/src/locales/pl-PL/index.json b/packages/ui/src/locales/pl-PL/index.json
index e56694e4a5..ecb1a186ab 100644
--- a/packages/ui/src/locales/pl-PL/index.json
+++ b/packages/ui/src/locales/pl-PL/index.json
@@ -4970,9 +4970,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Kopiuj ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Pobierz najnowszy backup"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Zarządzaj rozliczaniem"
},
diff --git a/packages/ui/src/locales/pt-BR/index.json b/packages/ui/src/locales/pt-BR/index.json
index ab7cbb2e9c..d84ee7d9d4 100644
--- a/packages/ui/src/locales/pt-BR/index.json
+++ b/packages/ui/src/locales/pt-BR/index.json
@@ -4967,9 +4967,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Copiar ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Baixe a cópia de segurança mais recente"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Gerenciar cobrança"
},
diff --git a/packages/ui/src/locales/ru-RU/index.json b/packages/ui/src/locales/ru-RU/index.json
index 5c29afac38..bb4601f509 100644
--- a/packages/ui/src/locales/ru-RU/index.json
+++ b/packages/ui/src/locales/ru-RU/index.json
@@ -5063,9 +5063,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Копировать ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Скачать последнюю резервную копию"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Управление платежами"
},
diff --git a/packages/ui/src/locales/sr-CS/index.json b/packages/ui/src/locales/sr-CS/index.json
index cb69a7a63f..8f3974545f 100644
--- a/packages/ui/src/locales/sr-CS/index.json
+++ b/packages/ui/src/locales/sr-CS/index.json
@@ -4400,9 +4400,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Kopiraj ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Instaliraj najnoviji backup"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Upravljaj naplatom"
},
diff --git a/packages/ui/src/locales/sv-SE/index.json b/packages/ui/src/locales/sv-SE/index.json
index ed05c880f8..d9b40071b4 100644
--- a/packages/ui/src/locales/sv-SE/index.json
+++ b/packages/ui/src/locales/sv-SE/index.json
@@ -4649,9 +4649,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Kopiera ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Ladda ner senaste säkerhetskopian"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Hantera användarfakturering"
},
diff --git a/packages/ui/src/locales/tr-TR/index.json b/packages/ui/src/locales/tr-TR/index.json
index 7c8b997e38..16502fc5c7 100644
--- a/packages/ui/src/locales/tr-TR/index.json
+++ b/packages/ui/src/locales/tr-TR/index.json
@@ -4913,9 +4913,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "ID'yi Kopyala"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Son yedeği indirin"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Faturalandırmayı yönetin"
},
diff --git a/packages/ui/src/locales/uk-UA/index.json b/packages/ui/src/locales/uk-UA/index.json
index 7f598a4ff6..6070e4fca9 100644
--- a/packages/ui/src/locales/uk-UA/index.json
+++ b/packages/ui/src/locales/uk-UA/index.json
@@ -4931,9 +4931,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Скопіювати ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Завантажити останню резервну копію"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Керування платежами"
},
diff --git a/packages/ui/src/locales/vi-VN/index.json b/packages/ui/src/locales/vi-VN/index.json
index aa5979c35b..eed81ec1d5 100644
--- a/packages/ui/src/locales/vi-VN/index.json
+++ b/packages/ui/src/locales/vi-VN/index.json
@@ -3908,9 +3908,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "Sao chép ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "Tải bản sao lưu mới nhất"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "Quản lý giao dịch"
},
diff --git a/packages/ui/src/locales/zh-CN/index.json b/packages/ui/src/locales/zh-CN/index.json
index 4af7731dd8..c1596c6f62 100644
--- a/packages/ui/src/locales/zh-CN/index.json
+++ b/packages/ui/src/locales/zh-CN/index.json
@@ -5153,9 +5153,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "复制 ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "下载最新备份"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "管理账单"
},
diff --git a/packages/ui/src/locales/zh-TW/index.json b/packages/ui/src/locales/zh-TW/index.json
index dbd709dd3b..9f5f79eaeb 100644
--- a/packages/ui/src/locales/zh-TW/index.json
+++ b/packages/ui/src/locales/zh-TW/index.json
@@ -5153,9 +5153,6 @@
"servers.listing.copy-id-label": {
"defaultMessage": "複製 ID"
},
- "servers.listing.download-latest-backup-tooltip": {
- "defaultMessage": "下載最新備份"
- },
"servers.listing.manage-billing-label": {
"defaultMessage": "管理帳務"
},
diff --git a/packages/ui/src/stories/servers/AuditLogTable.stories.ts b/packages/ui/src/stories/servers/AuditLogTable.stories.ts
index 646b108703..84077ea442 100644
--- a/packages/ui/src/stories/servers/AuditLogTable.stories.ts
+++ b/packages/ui/src/stories/servers/AuditLogTable.stories.ts
@@ -93,6 +93,7 @@ const serverFullResponse: Archon.Servers.v1.ServerFull = {
region: 'us-east',
region_should_be_user_displayed: true,
hostname: 'ashburn-01',
+ url_host: 'https://ashburn-01.example.com',
is_decommissioned_node: false,
},
},
@@ -102,6 +103,7 @@ const serverFullResponse: Archon.Servers.v1.ServerFull = {
name: 'Create SMP',
created_at: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString(),
is_active: false,
+ download_method: { method_type: 'direct_node_download' },
backups: [],
content: {
modloader: 'fabric',
@@ -120,6 +122,7 @@ const serverFullResponse: Archon.Servers.v1.ServerFull = {
name: 'SMP Season 4',
created_at: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString(),
is_active: true,
+ download_method: { method_type: 'direct_node_download' },
backups: [
{
id: backupId,
diff --git a/packages/ui/src/stories/servers/ServerListing.stories.ts b/packages/ui/src/stories/servers/ServerListing.stories.ts
index c890a6fba3..750622ed86 100644
--- a/packages/ui/src/stories/servers/ServerListing.stories.ts
+++ b/packages/ui/src/stories/servers/ServerListing.stories.ts
@@ -109,7 +109,7 @@ export const SetToCancel: Story = {
name: 'Survival SMP',
cancellationDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
onResubscribe: () => alert('Resubscribe clicked'),
- onDownloadBackup: () => alert('Download backup clicked'),
+ onDownloadWorld: () => alert('Download world clicked'),
},
}
@@ -121,19 +121,19 @@ export const SuspendedCancelled: Story = {
suspension_reason: 'cancelled',
cancellationDate: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
onResubscribe: () => alert('Resubscribe clicked'),
- onDownloadBackup: () => alert('Download backup clicked'),
+ onDownloadWorld: () => alert('Download world clicked'),
},
}
-export const SuspendedCancelledFilesExpired: Story = {
+export const SuspendedCancelledAfterResubscribeWindow: Story = {
args: {
...baseServer,
- onDownloadBackup: null,
+ onDownloadWorld: () => alert('Download world clicked'),
name: 'Old Event Server',
status: 'suspended',
suspension_reason: 'cancelled',
cancellationDate: new Date(2025, 1, 17).toISOString(),
- onResubscribe: () => alert('Resubscribe clicked'),
+ onResubscribe: null,
},
}
@@ -144,7 +144,7 @@ export const SuspendedPaymentFailed: Story = {
status: 'suspended',
suspension_reason: 'paymentfailed',
cancellationDate: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
- onDownloadBackup: () => alert('Download backup clicked'),
+ onDownloadWorld: () => alert('Download world clicked'),
},
}
@@ -154,7 +154,7 @@ export const SuspendedModerated: Story = {
name: 'Banned Server',
status: 'suspended',
suspension_reason: 'moderated',
- onDownloadBackup: () => alert('Download backup clicked'),
+ onDownloadWorld: () => alert('Download world clicked'),
},
}
@@ -163,6 +163,6 @@ export const SuspendedGeneric: Story = {
...baseServer,
name: 'Server with other suspension reason',
status: 'suspended',
- onDownloadBackup: () => alert('Download backup clicked'),
+ onDownloadWorld: () => alert('Download world clicked'),
},
}
diff --git a/packages/ui/src/utils/common-messages.ts b/packages/ui/src/utils/common-messages.ts
index 314863039e..d53deb76c5 100644
--- a/packages/ui/src/utils/common-messages.ts
+++ b/packages/ui/src/utils/common-messages.ts
@@ -124,6 +124,10 @@ export const commonMessages = defineMessages({
id: 'button.download',
defaultMessage: 'Download',
},
+ downloadFilesButton: {
+ id: 'button.download-files',
+ defaultMessage: 'Download files',
+ },
downloadingButton: {
id: 'button.downloading',
defaultMessage: 'Downloading',
diff --git a/packages/ui/src/utils/index.ts b/packages/ui/src/utils/index.ts
index d92f045915..b636f5ae64 100644
--- a/packages/ui/src/utils/index.ts
+++ b/packages/ui/src/utils/index.ts
@@ -11,6 +11,7 @@ export * from './notices'
export * from './project-types'
export * from './savable'
export * from './search'
+export * from './server-billing'
export * from './server-search'
export * from './tag-messages'
export * from './theme-color-transition'
diff --git a/packages/ui/src/utils/server-billing.ts b/packages/ui/src/utils/server-billing.ts
new file mode 100644
index 0000000000..ffff279d1b
--- /dev/null
+++ b/packages/ui/src/utils/server-billing.ts
@@ -0,0 +1,12 @@
+const SERVER_RESUBSCRIBE_WINDOW_MS = 30 * 24 * 60 * 60 * 1000
+
+export function isWithinServerResubscribeWindow(
+ cancellationDate: string | number | Date | null | undefined,
+): boolean {
+ if (cancellationDate == null) return false
+ const cancellationTime = new Date(cancellationDate).getTime()
+ return (
+ Number.isFinite(cancellationTime) &&
+ Date.now() <= cancellationTime + SERVER_RESUBSCRIBE_WINDOW_MS
+ )
+}
diff --git a/turbo.jsonc b/turbo.jsonc
index fae1c8dca6..f7ab6d9c34 100644
--- a/turbo.jsonc
+++ b/turbo.jsonc
@@ -48,12 +48,7 @@
"BUILD_ENV",
"PREVIEW"
],
- "passThroughEnv": [
- "SCCACHE_*",
- "RUSTC_WRAPPER",
- "AWS_ACCESS_KEY_ID",
- "AWS_SECRET_ACCESS_KEY"
- ]
+ "passThroughEnv": ["SCCACHE_*", "RUSTC_WRAPPER", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"]
},
"lint": {
"env": [
@@ -65,12 +60,7 @@
"FORCE_COLOR",
"NEXTEST_*"
],
- "passThroughEnv": [
- "SCCACHE_*",
- "RUSTC_WRAPPER",
- "AWS_ACCESS_KEY_ID",
- "AWS_SECRET_ACCESS_KEY"
- ]
+ "passThroughEnv": ["SCCACHE_*", "RUSTC_WRAPPER", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"]
},
"lint:ancillary": {},
"//#i18n:coverage": {
@@ -110,12 +100,7 @@
"FORCE_COLOR",
"NEXTEST_*"
],
- "passThroughEnv": [
- "SCCACHE_*",
- "RUSTC_WRAPPER",
- "AWS_ACCESS_KEY_ID",
- "AWS_SECRET_ACCESS_KEY"
- ]
+ "passThroughEnv": ["SCCACHE_*", "RUSTC_WRAPPER", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"]
},
"fix": {},
"fix:ancillary": {