mirror of https://github.com/TZGyn/shortener
migrate redirect to flyio for cheaper domain certs
parent
e7edf16138
commit
2723a9391c
Binary file not shown.
@ -0,0 +1,122 @@
|
||||
import { env } from '$env/dynamic/private'
|
||||
|
||||
class FlyioAPI {
|
||||
constructor(private apiKey: string) {}
|
||||
|
||||
private sendRequest(query: string, variables: any) {
|
||||
return fetch(`https://api.fly.io/graphql`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
},
|
||||
body: JSON.stringify({ query, variables }),
|
||||
})
|
||||
}
|
||||
|
||||
async checkDomain(domain: string) {
|
||||
const query = `
|
||||
query customDomainAvailable($domain: String!) {
|
||||
customDomainAvailable(domain: $domain) {
|
||||
__typename
|
||||
available
|
||||
message
|
||||
}
|
||||
}
|
||||
`
|
||||
const variables = {
|
||||
domain: domain,
|
||||
}
|
||||
const response = await this.sendRequest(query, variables)
|
||||
if (response.ok) {
|
||||
const data: any = await response.json()
|
||||
if (data.data.customDomainAvailable.available) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async createCustomDomain(domain: string) {
|
||||
const query = `
|
||||
mutation($appId: ID!, $hostname: String!) {
|
||||
addCertificate(appId: $appId, hostname: $hostname) {
|
||||
certificate {
|
||||
configured
|
||||
acmeDnsConfigured
|
||||
acmeAlpnConfigured
|
||||
certificateAuthority
|
||||
certificateRequestedAt
|
||||
dnsProvider
|
||||
dnsValidationInstructions
|
||||
dnsValidationHostname
|
||||
dnsValidationTarget
|
||||
hostname
|
||||
id
|
||||
source
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const variables = {
|
||||
appId: env.PRIVATE_FLYIO_APP_ID,
|
||||
hostname: domain,
|
||||
}
|
||||
const response = await this.sendRequest(query, variables)
|
||||
const data: any = await response.json()
|
||||
if (!data.errors) {
|
||||
return {
|
||||
success: true,
|
||||
} as const
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Something went wrong',
|
||||
} as const
|
||||
}
|
||||
}
|
||||
|
||||
async deleteCustomDomain(domain: string) {
|
||||
const query = `
|
||||
mutation ($appId: ID!, $hostname: String!) {
|
||||
deleteCertificate(appId: $appId, hostname: $hostname) {
|
||||
certificate {
|
||||
configured
|
||||
acmeDnsConfigured
|
||||
acmeAlpnConfigured
|
||||
certificateAuthority
|
||||
certificateRequestedAt
|
||||
dnsProvider
|
||||
dnsValidationInstructions
|
||||
dnsValidationHostname
|
||||
dnsValidationTarget
|
||||
hostname
|
||||
id
|
||||
source
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const variables = {
|
||||
appId: env.PRIVATE_FLYIO_APP_ID,
|
||||
hostname: domain,
|
||||
}
|
||||
const response = await this.sendRequest(query, variables)
|
||||
const data: any = await response.json()
|
||||
if (!data.errors) {
|
||||
console.log('Fly.io Delete Domain', data)
|
||||
return {
|
||||
success: true,
|
||||
} as const
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
} as const
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const flyioClient = new FlyioAPI(env.PRIVATE_FLYIO_API_KEY)
|
||||
@ -0,0 +1,72 @@
|
||||
<script lang="ts">
|
||||
import * as Tabs from '$lib/components/ui/tabs/index.js'
|
||||
import * as Card from '$lib/components/ui/card/index.js'
|
||||
import { Button } from '$lib/components/ui/button/index.js'
|
||||
import { Input } from '$lib/components/ui/input/index.js'
|
||||
import { Label } from '$lib/components/ui/label/index.js'
|
||||
|
||||
export let cname_record: string
|
||||
export let a_record: string
|
||||
export let aaaa_record: string
|
||||
|
||||
const defaultValue = cname_record ? 'cname' : 'a'
|
||||
</script>
|
||||
|
||||
<Tabs.Root value={defaultValue}>
|
||||
<Tabs.List>
|
||||
{#if cname_record}
|
||||
<Tabs.Trigger value="cname">CNAME</Tabs.Trigger>
|
||||
{/if}
|
||||
{#if a_record || aaaa_record}
|
||||
<Tabs.Trigger value="a">A and AAAA</Tabs.Trigger>
|
||||
{/if}
|
||||
</Tabs.List>
|
||||
{#if cname_record}
|
||||
<Tabs.Content value="cname">
|
||||
<Card.Root>
|
||||
<Card.Header class="grid grid-cols-[80px_1fr] space-y-0 py-4">
|
||||
<Card.Title>Type</Card.Title>
|
||||
<Card.Title>Value</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Footer class="bg-muted grid grid-cols-[80px_1fr] py-4">
|
||||
<Card.Description>CNAME</Card.Description>
|
||||
<Card.Description>{cname_record}</Card.Description>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
</Tabs.Content>
|
||||
{/if}
|
||||
{#if a_record || aaaa_record}
|
||||
<Tabs.Content value="a">
|
||||
<div class="flex flex-col gap-4">
|
||||
{#if a_record}
|
||||
<Card.Root>
|
||||
<Card.Header
|
||||
class="grid grid-cols-[80px_1fr] space-y-0 py-4">
|
||||
<Card.Title>Type</Card.Title>
|
||||
<Card.Title>Value</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Footer
|
||||
class="bg-muted grid grid-cols-[80px_1fr] py-4">
|
||||
<Card.Description>A</Card.Description>
|
||||
<Card.Description>{a_record}</Card.Description>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
{/if}
|
||||
{#if aaaa_record}
|
||||
<Card.Root>
|
||||
<Card.Header
|
||||
class="grid grid-cols-[80px_1fr] space-y-0 py-4">
|
||||
<Card.Title>Type</Card.Title>
|
||||
<Card.Title>Value</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Footer
|
||||
class="bg-muted grid grid-cols-[80px_1fr] py-4">
|
||||
<Card.Description>AAAA</Card.Description>
|
||||
<Card.Description>{aaaa_record}</Card.Description>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
{/if}
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
{/if}
|
||||
</Tabs.Root>
|
||||
@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import * as Tooltip from '$lib/components/ui/tooltip/index.js'
|
||||
import { InfoIcon } from 'lucide-svelte'
|
||||
|
||||
export let domain: string
|
||||
export let custom_ip: string | null
|
||||
export let cname_record: string
|
||||
export let a_record: string
|
||||
export let aaaa_record: string
|
||||
</script>
|
||||
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger class="flex items-center gap-1">
|
||||
<InfoIcon class="h-4 w-4" />
|
||||
{#if custom_ip}
|
||||
{custom_ip}
|
||||
{:else if cname_record}
|
||||
{cname_record}
|
||||
{:else if a_record}
|
||||
{a_record}
|
||||
{:else if aaaa_record}
|
||||
{aaaa_record}
|
||||
{:else}
|
||||
{'Public IP not found'}
|
||||
{/if}
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content>
|
||||
{#if custom_ip}
|
||||
<div>
|
||||
{'Create a CNAME/ALIAS record for ' +
|
||||
domain +
|
||||
' to ' +
|
||||
custom_ip}
|
||||
</div>
|
||||
{/if}
|
||||
{#if cname_record}
|
||||
<div>
|
||||
{'Create a CNAME/ALIAS record for ' +
|
||||
domain +
|
||||
' to ' +
|
||||
cname_record}
|
||||
</div>
|
||||
{/if}
|
||||
{#if a_record}
|
||||
<div>
|
||||
{'Create a A record for ' + domain + ' to ' + a_record}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if aaaa_record}
|
||||
<div>
|
||||
{'Create a AAAA record for ' + domain + ' to ' + aaaa_record}
|
||||
</div>
|
||||
{/if}
|
||||
{#if !(custom_ip || cname_record || a_record || aaaa_record)}
|
||||
<div>
|
||||
{'Public IP not found'}
|
||||
</div>
|
||||
{/if}
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
# fly.toml app configuration file generated for kon on 2024-07-28T10:01:44+08:00
|
||||
#
|
||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||
#
|
||||
|
||||
app = 'kon'
|
||||
primary_region = 'dfw'
|
||||
|
||||
[build]
|
||||
|
||||
[http_service]
|
||||
internal_port = 3000
|
||||
force_https = true
|
||||
auto_stop_machines = 'off'
|
||||
auto_start_machines = true
|
||||
min_machines_running = 0
|
||||
processes = ['app']
|
||||
|
||||
[[vm]]
|
||||
memory = '1gb'
|
||||
cpu_kind = 'shared'
|
||||
cpus = 1
|
||||
Loading…
Reference in New Issue