You've already forked AstralRinth
forked from didirus/AstralRinth
Merge commit '7fa442fb28a2b9156690ff147206275163e7aec8' into beta
This commit is contained in:
@@ -109,7 +109,7 @@ export const getAuthUrl = (provider, redirect = '/dashboard') => {
|
||||
const route = useNativeRoute()
|
||||
|
||||
const fullURL = route.query.launcher
|
||||
? 'https://launcher-files.modrinth.com'
|
||||
? getLauncherRedirectUrl(route)
|
||||
: `${config.public.siteUrl}/auth/sign-in?redirect=${redirect}`
|
||||
|
||||
return `${config.public.apiBaseUrl}auth/init?provider=${provider}&url=${encodeURIComponent(fullURL)}`
|
||||
@@ -131,3 +131,12 @@ export const removeAuthProvider = async (provider) => {
|
||||
|
||||
stopLoading()
|
||||
}
|
||||
|
||||
export const getLauncherRedirectUrl = (route) => {
|
||||
const usesLocalhostRedirectionScheme =
|
||||
['4', '6'].includes(route.query.ipver) && Number(route.query.port) < 65536
|
||||
|
||||
return usesLocalhostRedirectionScheme
|
||||
? `http://${route.query.ipver === '4' ? '127.0.0.1' : '[::1]'}:${route.query.port}`
|
||||
: `https://launcher-files.modrinth.com`
|
||||
}
|
||||
|
||||
187
apps/frontend/src/composables/avalara1099.ts
Normal file
187
apps/frontend/src/composables/avalara1099.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import type { Ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
export interface FormRequestAttributes {
|
||||
form_type: 'W-9' | 'W-8BEN' | 'W-8BEN-E' | string
|
||||
company_id: number
|
||||
company_name: string
|
||||
company_email: string
|
||||
reference_id: string | null
|
||||
form_id: string | null
|
||||
signed_at: string | null
|
||||
tin_match_status: string | null
|
||||
expires_at: string | null
|
||||
}
|
||||
|
||||
export interface FormRequestLinks {
|
||||
action_validate?: string
|
||||
action_complete?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface FormRequestData {
|
||||
id: string
|
||||
type: 'form_request' | string
|
||||
attributes: FormRequestAttributes
|
||||
links?: FormRequestLinks
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface FormRequestResponse {
|
||||
data: FormRequestData
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface UseAvalara1099Options {
|
||||
prefill?: Record<string, unknown>
|
||||
// Optional override for the origin (defaults to vendor CDN domain)
|
||||
origin?: string
|
||||
// Optional hook to further style the injected dialog/iframe
|
||||
styleDialog?: (dialog: HTMLDialogElement, iframe: HTMLIFrameElement | null) => void
|
||||
// Poll interval while waiting for global to appear
|
||||
pollIntervalMs?: number
|
||||
// Max time to wait for script before rejecting (ms); 0/undefined => no timeout
|
||||
timeoutMs?: number
|
||||
}
|
||||
|
||||
interface AvalaraGlobal {
|
||||
requestW9: (
|
||||
formRequest: FormRequestResponse | FormRequestData,
|
||||
opts?: { prefill?: Record<string, unknown> },
|
||||
) => Promise<FormRequestResponse> | any
|
||||
requestW8BEN: (
|
||||
formRequest: FormRequestResponse | FormRequestData,
|
||||
opts?: { prefill?: Record<string, unknown> },
|
||||
) => Promise<FormRequestResponse> | any
|
||||
requestW8BENE: (
|
||||
formRequest: FormRequestResponse | FormRequestData,
|
||||
opts?: { prefill?: Record<string, unknown> },
|
||||
) => Promise<FormRequestResponse> | any
|
||||
origin?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Avalara1099?: AvalaraGlobal
|
||||
}
|
||||
}
|
||||
|
||||
const injectedKey = '__avalara1099_script_injected__'
|
||||
|
||||
function ensureScriptInjected(origin: string) {
|
||||
if (import.meta.server) return
|
||||
const w = window as any
|
||||
if (w[injectedKey]) return
|
||||
w[injectedKey] = true
|
||||
useHead({
|
||||
script: [
|
||||
{
|
||||
src: `${origin.replace(/\/$/, '')}/api/request_form.js`,
|
||||
crossorigin: 'anonymous',
|
||||
type: 'module',
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
async function waitForAvalara(opts: {
|
||||
pollIntervalMs: number
|
||||
timeoutMs?: number
|
||||
origin: string
|
||||
}): Promise<AvalaraGlobal> {
|
||||
if (import.meta.server) throw new Error('Avalara 1099 is client-side only')
|
||||
ensureScriptInjected(opts.origin)
|
||||
const start = Date.now()
|
||||
return await new Promise((resolve, reject) => {
|
||||
const poll = () => {
|
||||
const g = window.Avalara1099
|
||||
if (g) return resolve(g)
|
||||
if (opts.timeoutMs && opts.timeoutMs > 0 && Date.now() - start > opts.timeoutMs) {
|
||||
return reject(new Error('Timed out waiting for Avalara1099 script to load'))
|
||||
}
|
||||
setTimeout(poll, opts.pollIntervalMs)
|
||||
}
|
||||
poll()
|
||||
})
|
||||
}
|
||||
|
||||
export function useAvalara1099(
|
||||
initial: FormRequestResponse | FormRequestData,
|
||||
options: UseAvalara1099Options = {},
|
||||
) {
|
||||
const origin = options.origin || 'https://www.track1099.com'
|
||||
const pollIntervalMs = options.pollIntervalMs ?? 250
|
||||
const timeoutMs = options.timeoutMs
|
||||
|
||||
const request: Ref<FormRequestResponse | FormRequestData> = ref(initial)
|
||||
const loading = ref(false)
|
||||
const error: Ref<unknown> = ref(null)
|
||||
|
||||
const signedAt = computed(() => {
|
||||
const data = (request.value as FormRequestResponse).data || request.value
|
||||
return data.attributes?.signed_at ? new Date(data.attributes.signed_at) : null
|
||||
})
|
||||
|
||||
const status = computed(() => (signedAt.value ? 'signed' : 'incomplete'))
|
||||
|
||||
async function start(): Promise<FormRequestResponse | FormRequestData> {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
const g = await waitForAvalara({ pollIntervalMs, timeoutMs, origin })
|
||||
const data = (request.value as FormRequestResponse).data || request.value
|
||||
const formType = data.attributes?.form_type
|
||||
|
||||
// Defensive deep clone to strip proxies / non-cloneable refs before postMessage
|
||||
// (DataCloneError guard)
|
||||
let safeRequest: any
|
||||
try {
|
||||
safeRequest = JSON.parse(JSON.stringify(request.value))
|
||||
} catch {
|
||||
// Fallback shallow copy
|
||||
safeRequest = Array.isArray(request.value)
|
||||
? [...(request.value as any)]
|
||||
: { ...(request.value as any) }
|
||||
}
|
||||
let safePrefill: any = undefined
|
||||
if (options.prefill) {
|
||||
try {
|
||||
safePrefill = JSON.parse(JSON.stringify(options.prefill))
|
||||
} catch {
|
||||
safePrefill = { ...options.prefill }
|
||||
}
|
||||
}
|
||||
|
||||
let promise: any
|
||||
if (formType === 'W-8BEN') {
|
||||
promise = g.requestW8BEN(safeRequest, { prefill: safePrefill })
|
||||
} else if (formType === 'W-9') {
|
||||
promise = g.requestW9(safeRequest, { prefill: safePrefill })
|
||||
} else if (formType === 'W-8BEN-E' || formType === 'W-8BEN E') {
|
||||
promise = g.requestW8BENE(safeRequest, { prefill: safePrefill })
|
||||
} else {
|
||||
throw new Error(`Unsupported form_type: ${formType}`)
|
||||
}
|
||||
|
||||
// The vendor promise resolves with an updated form request (signed state)
|
||||
const newReq = await promise
|
||||
request.value = newReq
|
||||
return newReq
|
||||
} catch (e) {
|
||||
error.value = e
|
||||
throw e
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
start,
|
||||
request,
|
||||
signedAt,
|
||||
status, // 'signed' | 'incomplete'
|
||||
loading,
|
||||
error,
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,11 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({
|
||||
showVersionFilesInTable: false,
|
||||
// showAdsWithPlus: false,
|
||||
alwaysShowChecklistAsPopup: true,
|
||||
testTaxForm: false,
|
||||
|
||||
// Feature toggles
|
||||
projectTypesPrimaryNav: false,
|
||||
enableMedalPromotion: true,
|
||||
hidePlusPromoInUserMenu: false,
|
||||
oldProjectCards: true,
|
||||
newProjectCards: false,
|
||||
@@ -34,6 +36,9 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({
|
||||
showProjectPageDownloadModalServersPromo: false,
|
||||
showProjectPageCreateServersTooltip: true,
|
||||
showProjectPageQuickServerButton: false,
|
||||
newProjectGeneralSettings: false,
|
||||
newProjectEnvironmentSettings: true,
|
||||
hideRussiaCensorshipBanner: false,
|
||||
// advancedRendering: true,
|
||||
// externalLinksNewTab: true,
|
||||
// notUsingBlockers: false,
|
||||
|
||||
@@ -41,12 +41,6 @@ export class BackupsModule extends ServerModule {
|
||||
await this.fetch() // Refresh this module
|
||||
}
|
||||
|
||||
async prepare(backupId: string): Promise<void> {
|
||||
await useServersFetch(`servers/${this.serverId}/backups/${backupId}/prepare-download`, {
|
||||
method: 'POST',
|
||||
})
|
||||
}
|
||||
|
||||
async lock(backupId: string): Promise<void> {
|
||||
await useServersFetch(`servers/${this.serverId}/backups/${backupId}/lock`, {
|
||||
method: 'POST',
|
||||
|
||||
@@ -34,6 +34,8 @@ export class GeneralModule extends ServerModule implements ServerGeneral {
|
||||
node!: { token: string; instance: string }
|
||||
flows?: { intro?: boolean }
|
||||
|
||||
is_medal?: boolean
|
||||
|
||||
async fetch(): Promise<void> {
|
||||
const data = await useServersFetch<ServerGeneral>(`servers/${this.serverId}`, {}, 'general')
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ export const initUserProjects = async () => {
|
||||
if (auth.user && auth.user.id) {
|
||||
try {
|
||||
user.projects = await useBaseFetch(`user/${auth.user.id}/projects`)
|
||||
user.projectsV3 = await useBaseFetch(`user/${auth.user.id}/projects`, { apiVersion: 3 })
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user