Daemon-based proxy and Docker updates

This commit is contained in:
Ben Allfree 2022-10-12 19:01:22 -07:00
parent cfd04716c6
commit 72057c6934
47 changed files with 1681 additions and 2434 deletions

6
.env.template Normal file
View File

@ -0,0 +1,6 @@
APP_DOMAIN = pockethost.local
CORE_PB_SUBDOMAIN = pockethost-central
CORE_PB_USERNAME = ben@pockethost.io
CORE_PB_PASSWORD =
CORE_PB_PORT = 8090
PB_IDLE_TTL = 5000

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
.DS_Store
node_modules
.secret
.vscode
.vscode
.env

9
.yarnrc.yml Normal file
View File

@ -0,0 +1,9 @@
supportedArchitectures:
os:
- 'current'
- 'darwin'
- 'linux'
- 'win32'
cpu:
- 'current'
- 'arm64'

View File

@ -0,0 +1,55 @@
version: '3'
services:
app:
image: node:18
container_name: www
restart: unless-stopped
command: node index.js
working_dir: /mount/repo/packages/pockethost.io/dist-server
volumes:
- ..:/mount/repo
networks:
- app-network
ports:
- '9000:3000'
depends_on:
- pbproxy
env_file:
- ../.env
pbproxy:
env_file:
- ../.env
image: node:18
container_name: pbproxy
restart: unless-stopped
command: yarn serve
working_dir: /mount/repo/packages/daemon/
volumes:
- ..:/mount/repo
- ../packages/pocketbase/pocketbase:/mount/pocketbase/bin/pocketbase
- ./mount/pocketbase/instances:/mount/pocketbase/instances
networks:
- app-network
ports:
- '9001:3000'
nginx:
image: nginx:mainline-alpine
container_name: nginx
restart: unless-stopped
depends_on:
- app
- pbproxy
ports:
- '80:80'
- '443:443'
volumes:
- ./nginx-conf:/etc/nginx/conf.d
- ./mount/logs:/mount/logs
- ./mount/ssl:/mount/ssl
networks:
- app-network
networks:
app-network:
driver: bridge

2
docker/mount/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
pocketbase
logs/*

4
docker/mount/ssl/mk.sh Normal file
View File

@ -0,0 +1,4 @@
openssl req -x509 -out pockethost.local.crt -keyout pockethost.local.key \
-newkey rsa:2048 -nodes -sha256 \
-subj '/CN=pockethost.local' -extensions EXT -config <( \
printf "[dn]\nCN=pockethost.local\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:pockethost.local\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIJAN2tVmx5CDN7MA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
BAMMEHBvY2tldGhvc3QubG9jYWwwHhcNMjIxMDEyMDQ0MzE2WhcNMjIxMTExMDQ0
MzE2WjAbMRkwFwYDVQQDDBBwb2NrZXRob3N0LmxvY2FsMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAxwuaR/H2qArNSrgQEfZMg5peZYqGSzhov30QrS4N
0YA/iRd6h0DLW76fJ+kta0Zx7J34EnYOodEW5tQ3dCQrGmHHlTVsR4iIMuk1ClEC
0OmDhVJc/hFvGIdeJhF7lsJ+NmUBKgYB5phEn21EOrHhTBREdIMjU3mnXiBCnCRF
cNti9/t1hLx0yXohCq8HNjEJEMk7QZdiFISPLeuf8a6Tp3NtMLcdfCVB3V80FReP
Vhl/Q0dx4nWuqbU6poAbfVr2Ot/bbtd4ZqhjI89vBDZWKC8tDNfvuRM/eKYc0VT5
lg4I0hR1yLz8I6LZYpo2L6FUKA42PPI1D4zJTMBqbOpUmQIDAQABo0EwPzAbBgNV
HREEFDASghBwb2NrZXRob3N0LmxvY2FsMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAK
BggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEAPEBYhHTVikaeXCmU9Mlm3fe4
UaofK7gd+CV2HvclW3BiiEFhBsiuIw/33PRJG3caj2EYYdW5TytKJ1962dwIiod8
ve2XnHiIzP5ECgBiiGSu1BQCK4Olg9u6JRXPDsa1/qpuodikXnxWCVHiCwUDuECt
rKk6BggvzPfRv6X+DZkoyc4sx2NJbUTYyLBZq+v9DSX7WGP/3ZbUTQ3UHVyFSM3d
vTgbLTgfjNuwFx9WFg7JMfp4+GoNX4pei2nOagfqP8BUODQEkBcwZV1UZEO4Gbi/
tw6ze/jJqIb80lu2U7hNzzsCKhVnYs+EBNPo88Cn+bpHVmxlK6T1M/OhMUGt0g==
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHC5pH8faoCs1K
uBAR9kyDml5lioZLOGi/fRCtLg3RgD+JF3qHQMtbvp8n6S1rRnHsnfgSdg6h0Rbm
1Dd0JCsaYceVNWxHiIgy6TUKUQLQ6YOFUlz+EW8Yh14mEXuWwn42ZQEqBgHmmESf
bUQ6seFMFER0gyNTeadeIEKcJEVw22L3+3WEvHTJeiEKrwc2MQkQyTtBl2IUhI8t
65/xrpOnc20wtx18JUHdXzQVF49WGX9DR3Hida6ptTqmgBt9WvY639tu13hmqGMj
z28ENlYoLy0M1++5Ez94phzRVPmWDgjSFHXIvPwjotlimjYvoVQoDjY88jUPjMlM
wGps6lSZAgMBAAECggEAKYeoNx6rIkCuuMpSwAytxj+tNm6CuqsYX+vOUPPs+itS
Fl6JuDKyu3+4YXFrgph+KKqFGgT75JNlvd/FejwZqjWAmQc+gmZgVI8H/BEPD1vJ
j0WyFWi5z1pfMH4xVTFbeCn25je+qchXeRQpSj3XDjKkXdMGyeH2I9ODUmTXAEbH
zA/FuBg+M3leqjak1mcog/e/FIkpZwJq2rMmwehe03gFZdJQgExjhBOXT6haVXQY
0SsjQG70gli9tLwVL/JIvhE6W5oaGsT1SyI76GWwBIL2WHrT53VdgFhienaHIRlg
KwcpfF2pBkuTtQLLDgvUOKSHHO5Rc93SqycDzXN1iQKBgQDpx6scQOFa86aown9b
6QwF9KiQgG2i1bCyifRyGjSQuOpgN22Dgq1hNczh+84Souz7WsNgiHzU2Bu1NqXC
/UJH5PcZv2qiqIifqLnKWWyNpK9+JyuP89wmrGIjylbbzhukY4qyb7WnDyH+FDU4
/dRhMrFAc7Et5oAVgaOep74kBwKBgQDZ9sWDUP/KMtfitCXzn0uZWU4ahIAXru+v
UCrS1aiAmDZvOl6QTXl0IpbwDHzcCMLh8TQeUJt8rD7Limd4lrjZw2TfjKtLv2op
jLEWof8h2YZxwz2vOEE53aQvyoC57Tse94Sy2Bb+vJM9xWrdzSLp9pWw+bdhDu2A
g+a1vqvaXwKBgBrA6ugU1LVf5NazS3ftN58G3LOMvv8/jTUhbIQSU6msP8Y7EaFX
NxhE2+mQs4iWdKBfRrSpaf/Bq4oVcurZqNgpb83WhhGPT/NVj82EZlPfYOYC/Y0/
zxXt7F1ELqSA9dDeQ2UgO52esbkt/tlC0yc8ceR6WPBzzHyplVv2vl/JAoGBANQ0
IbWoXXBBMdfAZhaa5uJEhPriN0dXhHkdRqP/ac7Q4mZF4J0DIJTFvEe3ELS0Pu/0
gjZlagvmMji95eEMdKlmR0Yx0O+tSzFqjVqomxkci30khWCbFz28IMZ6k/rwERgk
COiJ41FczMld854/wpcgADrN1BBFlUsCn9If8XZnAoGAN8AwAT+6/EucEOlcgSO0
eVxBmvnABj8fNGylTJxIpwlJabkOl324bKbrTiqvY5zTKFWr3AhPOmckXcWhLycy
4TCqlBIWl76lt37zgPwPGiuSfaubKbWsbWDjfk27qlt2MNsG7IHYOfldWJkxPiyK
i0hsIapEVqcWsDaXo/3i1mE=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,85 @@
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
server {
# dev
server_name www.pockethost.local;
return 301 $scheme://pockethost.local$request_uri;
# prod
# server_name www.pockethost.io;
# return 301 $scheme://pockethost.io$request_uri;
}
server {
listen 443 ssl;
# dev
server_name pockethost.local;
ssl_certificate /mount/ssl/pockethost.local.crt;
ssl_certificate_key /mount/ssl/pockethost.local.key;
# prod
# server_name pockethost.io;
# ssl_certificate /mount/ssl/fullchain.pem;
# ssl_certificate_key /mount/ssl/privkey.pem;
access_log /mount/logs/access.log;
error_log /mount/logs/error.log;
location / {
proxy_read_timeout 180s;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://www:3000;
}
}
server {
listen 443 ssl;
# dev
server_name *.pockethost.local;
ssl_certificate /mount/ssl/pockethost.local.crt;
ssl_certificate_key /mount/ssl/pockethost.local.key;
# prod
# server_name *.pockethost.io;
# ssl_certificate /mount/ssl/fullchain.pem;
# ssl_certificate_key /mount/ssl/privkey.pem;
access_log /mount/logs/access.log;
error_log /mount/logs/error.log;
location / {
proxy_read_timeout 180s;
# WebSocket support
proxy_buffering off; # For realtime
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://pbproxy:3000;
}
}

View File

@ -1,19 +1,14 @@
{
"name": "pockethost",
"version": "0.0.1",
"version": "0.2.0",
"author": "Ben Allfree <ben@benallfree.com>",
"license": "MIT",
"private": true,
"scripts": {
"sync": "rsync -avv --exclude-from=.rsyncignore ./* pockethost@pockethost.io:~/pockethost --delete",
"watch": "chokidar './**/*' -i .git -i '**/node_modules' -i '.svelte-kit' -c 'yarn sync' --initial"
"workspaces": {
"packages": [
"packages/*"
]
},
"workspaces": [
"packages/fcs-client",
"packages/worker",
"packages/admin",
"packages/*"
],
"prettier": {
"semi": false,
"useTabs": false,

View File

@ -4,8 +4,8 @@
"main": "src/index.ts",
"license": "MIT",
"dependencies": {
"@s-libs/micro-dash": "^14.1.0",
"nanoid": "^4.0.0",
"pocketbase": "^0.7.0",
"ts-brand": "^0.0.2"
"pocketbase": "^0.7.0"
}
}

View File

@ -1,7 +1,7 @@
import { pocketbase } from './pocketbase'
import PocketBase from 'pocketbase'
import { Any_Record_Out } from './schema'
export const createRealtimeSubscriptionManager = () => {
export const createRealtimeSubscriptionManager = (pocketbase: PocketBase) => {
const subscriptions: { [_: string]: number } = {}
const subscribe = <TRec extends Any_Record_Out>(

View File

@ -0,0 +1,3 @@
export * from './assert'
export * from './pocketbase'
export * from './schema'

View File

@ -1,87 +1,113 @@
import pocketbaseEs, { BaseAuthStore } from 'pocketbase'
import { map } from '@s-libs/micro-dash'
import PocketBase, {
BaseAuthStore,
ClientResponseError,
Record,
} from 'pocketbase'
import type { Unsubscriber } from 'svelte/store'
import { identity } from 'ts-brand'
import { createRealtimeSubscriptionManager } from './RealtimeSubscriptionManager'
import type {
InstanceId,
Instance_In,
Instance_Out,
Instance_Out_ByIdCollection,
} from './schema'
import type { InstanceId, Instance_In, Instance_Out } from './schema'
const client = new pocketbaseEs('https://pockethost-central.pockethost.io')
export const createPocketbaseClient = (url: string) => {
const client = new PocketBase(url)
const { authStore } = client
const { authStore } = client
const { onChange } = authStore
const { onChange } = authStore
export const user = () => authStore.model
const user = () => authStore.model
export const isLoggedIn = () => authStore.isValid
const isLoggedIn = () => authStore.isValid
export const onAuthChange = (cb: (user: BaseAuthStore) => Unsubscriber) =>
onChange(() => cb(authStore))
const onAuthChange = (cb: (user: BaseAuthStore) => Unsubscriber) =>
onChange(() => cb(authStore))
export const logOut = () => authStore.clear()
const logOut = () => authStore.clear()
export const createUser = (email: string, password: string) =>
client.users.create({
email,
password,
passwordConfirm: password,
})
const createUser = (email: string, password: string) =>
client.users.create({
email,
password,
passwordConfirm: password,
})
export const authViaEmail = (email: string, password: string) =>
client.users.authViaEmail(email, password)
const authViaEmail = (email: string, password: string) =>
client.users.authViaEmail(email, password)
export const pocketbase = client
const createInstance = (payload: Instance_In): Promise<Instance_Out> => {
return client.records
.create('instances', payload)
.then((r) => r as unknown as Instance_Out)
}
export const createInstance = (payload: Instance_In): Promise<Instance_Out> => {
return pocketbase.records
.create('instances', payload)
.then((r) => r as unknown as Instance_Out)
}
const getInstanceById = (id: InstanceId): Promise<Instance_Out | undefined> =>
client.records
.getOne('instances', id)
.then((r) => r as unknown as Instance_Out)
export const getInstanceById = (
id: InstanceId
): Promise<Instance_Out | undefined> =>
pocketbase.records
.getOne('instances', id)
.then((r) => r as unknown as Instance_Out)
const subscribe = createRealtimeSubscriptionManager(client)
const subscribe = createRealtimeSubscriptionManager()
const watchInstanceById = (
id: InstanceId,
cb: (rec: Instance_Out) => void
): Unsubscriber => {
const slug = `instances/${id}`
getInstanceById(id).then((v) => {
if (!v) return
console.log(`Initial record`, { v })
cb(v)
})
return subscribe(slug, cb)
}
export const watchInstanceById = (
id: InstanceId,
cb: (rec: Instance_Out) => void
): Unsubscriber => {
const slug = `instances/${id}`
getInstanceById(id).then((v) => {
if (!v) return
console.log(`Initial record`, { v })
cb(v)
})
return subscribe(slug, cb)
}
const getAllInstancesById = async () =>
(
await client.records.getFullList('instances').catch((e) => {
console.error(`getAllInstancesById failed with ${e}`)
throw e
})
).reduce((c, v) => {
c[v.id] = v
return c
}, {} as Record)
export const getAllInstancesById = async () =>
(
await client.records.getFullList('instances').catch((e) => {
console.error(`getAllInstancesById failed with ${e}`)
const setInstance = (instanceId: InstanceId, fields: Instance_In) => {
console.log(`${instanceId} setting fields`, { fields })
return client.records.update('instances', instanceId, fields).catch((e) => {
console.error(`setInstance failed for ${instanceId} with ${e}`, {
fields,
})
throw e
})
).reduce((c, v) => {
const _v = identity<Instance_Out>(v)
c[_v.id] = _v
return c
}, {} as Instance_Out_ByIdCollection)
}
export const setInstance = (instanceId: InstanceId, fields: Instance_In) => {
console.log(`${instanceId} setting fields`, { fields })
return client.records.update('instances', instanceId, fields).catch((e) => {
console.error(`setInstance failed for ${instanceId} with ${e}`, {
fields,
})
throw e
})
const parseError = (e: any): string[] => {
if (e instanceof ClientResponseError) {
const { data } = e
if (!data || !data.data) {
return [`Unknown error ${e.message}`]
}
return map(data.data, (v, k) => (v ? v.message : undefined)).filter(
(v) => !!v
)
} else {
return [`Unknown error ${e.message}`]
}
}
return {
parseError,
subscribe,
getInstanceById,
createInstance,
authViaEmail,
createUser,
logOut,
onAuthChange,
isLoggedIn,
user,
watchInstanceById,
getAllInstancesById,
setInstance,
}
}

View File

@ -1,34 +1,32 @@
import { AnyBrand, Brand, identity } from 'ts-brand'
export type RecordId = string
export type UserId = RecordId
export type InstanceId = RecordId
export type InternalInstanceId = RecordId
export type Subdomain = string
export type Port = number
export type IsoDate = string
export type ProcessId = number
export type Username = string
export type Password = string
export type UserId = Brand<string, 'UserId'>
export type InstanceId = Brand<string, 'InstanceId'>
export type InternalInstanceId = Brand<string, 'InternalInstanceId'>
export type Subdomain = Brand<string, 'Subdomain'>
export type Port = Brand<number, 'Port'>
export type IsoDate = Brand<string, 'IsoDate'>
export type ProcessId = Brand<number, 'ProcessId'>
export type Username = Brand<string, 'username'>
export type Password = Brand<string, 'password'>
export const pocketNow = () => new Date().toISOString()
export const pocketNow = () => identity<IsoDate>(new Date().toISOString())
export enum InstanceStatuses {
export enum InstanceStatus {
Unknown = '',
Provisioning = 'provisioning',
Port = 'obtaining port',
Cert = 'creating SSL cert',
Idle = 'idle',
Port = 'porting',
Starting = 'starting',
Started = 'started',
Running = 'running',
Failed = 'failed',
}
export type Instance_In = {
uid?: UserId
subdomain?: Subdomain
status?: InstanceStatuses
status?: InstanceStatus
}
export type PocketbaseRecord<TIdType extends AnyBrand> = {
export type PocketbaseRecord<TIdType extends RecordId> = {
id: TIdType
created: IsoDate
updated: IsoDate
@ -37,7 +35,7 @@ export type PocketbaseRecord<TIdType extends AnyBrand> = {
export type Instance_Out = PocketbaseRecord<InstanceId> & {
uid: UserId
subdomain: Subdomain
status: InstanceStatuses
status: InstanceStatus
}
export type Instance_Internal_In = {

View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"module": "ESNext",
"moduleResolution": "node",
"noUncheckedIndexedAccess": true,
"strictNullChecks": true,
"noEmit": true,
"types": ["vite/client"]
},
"include": ["./src"]
}

View File

@ -3,7 +3,8 @@
"version": "0.0.1",
"license": "MIT",
"scripts": {
"build": "parcel",
"build": "esbuild src/server.ts --bundle --platform=node > dist/server.js",
"watch": "chokidar 'src/**' -c 'yarn build' --initial",
"serve": "node dist/server.js"
},
"targets": {
@ -23,13 +24,18 @@
"dependencies": {
"@pockethost/common": "0.0.1",
"@s-libs/micro-dash": "^14.1.0",
"@types/http-proxy": "^1.17.9",
"bottleneck": "^2.19.5",
"chokidar-cli": "^3.0.0",
"event-source-polyfill": "^1.0.31",
"get-port": "^6.1.2",
"http-proxy": "^1.18.1",
"node-fetch": "^3.2.10",
"pocketbase": "^0.7.0",
"ts-brand": "^0.0.2"
"ts-node": "^10.9.1"
},
"devDependencies": {
"chokidar-cli": "^3.0.0",
"parcel": "^2.7.0",
"ts-node": "^10.9.1"
}

View File

@ -0,0 +1,166 @@
import { InstanceStatus } from '@pockethost/common'
import { map } from '@s-libs/micro-dash'
import Bottleneck from 'bottleneck'
import { ChildProcessWithoutNullStreams, spawn } from 'child_process'
import getPort from 'get-port'
import fetch from 'node-fetch'
import {
CORE_PB_PASSWORD,
CORE_PB_PORT,
CORE_PB_SUBDOMAIN,
CORE_PB_USERNAME,
PB_IDLE_TTL,
} from './constants'
import { createPbClient } from './PbClient'
type Instance = {
process: ChildProcessWithoutNullStreams
internalUrl: string
port: number
heartbeat: (shouldStop?: boolean) => void
}
const ROOT_DIR = `/mount/pocketbase`
const BIN_ROOT = `${ROOT_DIR}/bin`
const INSTANCES_ROOT = `${ROOT_DIR}/instances`
const tryFetch = (url: string) =>
new Promise<void>((resolve, reject) => {
const tryFetch = () => {
console.log(`Trying to connect to instance ${url} `)
fetch(url)
.then(() => {
console.log(`Connection successful`)
resolve()
})
.catch((e) => {
console.error(`Could not connect`)
setTimeout(tryFetch, 1000)
})
}
tryFetch()
})
const mkInternalAddress = (port: number) => `127.0.0.1:${port}`
const mkInternalUrl = (port: number) => `http://${mkInternalAddress(port)}`
export const createInstanceManger = async () => {
const instances: { [_: string]: Instance } = {}
const _spawn = async (cfg: { subdomain: string; port: number }) => {
const { subdomain, port } = cfg
const cmd = `${BIN_ROOT}/pocketbase`
const args = [
`serve`,
`--dir`,
`${INSTANCES_ROOT}/${subdomain}/pb_data`,
`--http`,
mkInternalAddress(port),
]
console.log(`Spawning ${subdomain}`, { cmd, args })
const ls = spawn(cmd, args)
ls.stdout.on('data', (data) => {
console.log(`${subdomain} stdout: ${data}`)
})
ls.stderr.on('data', (data) => {
console.error(`${subdomain} stderr: ${data}`)
})
ls.on('close', (code) => {
console.log(`${subdomain} closed with code ${code}`)
})
ls.on('exit', (code) => {
instances[subdomain]?.heartbeat(true)
delete instances[subdomain]
client.updateInstanceStatus(subdomain, InstanceStatus.Idle)
console.log(`${subdomain} exited with code ${code}`)
})
ls.on('error', (err) => {
console.log(`${subdomain} had error ${err}`)
})
await tryFetch(mkInternalUrl(port))
return ls
}
const coreInternalUrl = mkInternalUrl(CORE_PB_PORT)
const client = createPbClient(coreInternalUrl)
const mainProcess = await _spawn({
subdomain: CORE_PB_SUBDOMAIN,
port: CORE_PB_PORT,
})
instances[CORE_PB_SUBDOMAIN] = {
process: mainProcess,
internalUrl: coreInternalUrl,
port: CORE_PB_PORT,
heartbeat: () => {},
}
await tryFetch(coreInternalUrl)
await client.adminAuthViaEmail(CORE_PB_USERNAME, CORE_PB_PASSWORD)
const limiter = new Bottleneck({ maxConcurrent: 1 })
const getInstance = (subdomain: string) =>
limiter.schedule(async () => {
console.log(`Getting instance ${subdomain}`)
const instance = instances[subdomain]
if (instance) {
console.log(`Found in cache: ${subdomain}`)
instance.heartbeat()
return instance
}
console.log(`Checking ${subdomain} for permission`)
const recs = await client.getInstanceBySubdomain(subdomain)
const [item] = recs.items
if (!item) {
console.log(`${subdomain} not found`)
return
}
await client.updateInstanceStatus(subdomain, InstanceStatus.Port)
console.log(`${subdomain} found in DB`)
const exclude = map(instances, (i) => i.port)
const newPort = await getPort({
port: 8090,
exclude,
}).catch((e) => {
console.error(`Failed to get port`)
throw e
})
console.log(`Found port for ${subdomain}: ${newPort}`)
await client.updateInstanceStatus(subdomain, InstanceStatus.Starting)
const childProcess = await _spawn({ subdomain, port: newPort })
const internalUrl = mkInternalUrl(newPort)
const api: Instance = {
process: childProcess,
internalUrl,
port: newPort,
heartbeat: (() => {
let tid: ReturnType<typeof setTimeout>
const _cleanup = () => {
childProcess.kill()
}
tid = setTimeout(_cleanup, PB_IDLE_TTL)
return (shouldStop) => {
clearTimeout(tid)
if (!shouldStop) {
tid = setTimeout(_cleanup, PB_IDLE_TTL)
}
}
})(),
}
instances[subdomain] = api
await client.updateInstanceStatus(subdomain, InstanceStatus.Running)
console.log(`${internalUrl} is running`)
return instances[subdomain]
})
return { getInstance }
}

View File

@ -0,0 +1,51 @@
import { InstanceStatus } from '@pockethost/common'
import PocketBase from 'pocketbase'
const safeCatch = <TIn extends any[], TOut>(
name: string,
cb: (...args: TIn) => Promise<TOut>
) => {
return (...args: TIn) => {
console.log(`${name}`)
return cb(...args).catch((e: any) => {
console.error(`${name} failed: ${e}`)
throw e
})
}
}
export const createPbClient = (url: string) => {
console.log(`Initializing client: ${url}`)
const client = new PocketBase(url)
const adminAuthViaEmail = safeCatch(
`adminAuthViaEmail`,
(email: string, password: string) =>
client.admins.authViaEmail(email, password)
)
const getInstanceBySubdomain = safeCatch(
`getInstanceBySubdomain`,
(subdomain: string) =>
client.records.getList(`instances`, 1, 1, {
filter: `subdomain = '${subdomain}'`,
})
)
const updateInstanceStatus = safeCatch(
`updateInstanceStatus`,
async (subdomain: string, status: InstanceStatus) => {
const recs = await getInstanceBySubdomain(subdomain)
if (recs.totalItems !== 1) {
throw new Error(`Expected just one subdomain record for ${subdomain}`)
}
const [item] = recs.items
if (!item) {
throw new Error(`Expected item here for ${subdomain}`)
}
await client.records.update(`instances`, item.id, { status })
}
)
return { adminAuthViaEmail, getInstanceBySubdomain, updateInstanceStatus }
}

View File

@ -0,0 +1,45 @@
import { createServer } from 'http'
import httpProxy from 'http-proxy'
import { createInstanceManger } from './InstanceManager'
export const createProxyServer = async () => {
const instanceManager = await createInstanceManger()
const proxy = httpProxy.createProxyServer({})
const server = createServer(async (req, res) => {
console.log(`Incoming request ${req.headers.host}/${req.url}`)
const die = (msg: string) => {
console.error(`ERROR: ${msg}`)
res.writeHead(200, {
'Content-Type': `text/plain`,
})
res.end(msg)
}
const host = req.headers.host
if (!host) {
die(`Host not found`)
return
}
const [subdomain, ...junk] = host.split('.')
if (!subdomain) {
die(`${host} has no subdomain.`)
return
}
const instance = await instanceManager.getInstance(subdomain)
if (!instance) {
die(
`${host} not found. Please check the instance URL and try again, or create one at https://pockethost.io`
)
return
}
console.log(
`Forwarding proxy request for ${req.url} to instance ${instance.internalUrl}`
)
proxy.web(req, res, { target: instance.internalUrl })
})
console.log('daemon on port 3000')
server.listen(3000)
}

View File

@ -0,0 +1,23 @@
export const APP_DOMAIN = process.env.APP_DOMAIN || `pockethost.local`
export const CORE_PB_SUBDOMAIN =
process.env.CORE_PB_SUBDOMAIN || `pockethost-central`
export const CORE_PB_USERNAME = (() => {
const v = process.env.CORE_PB_USERNAME
if (!v) {
throw new Error(`CORE_PB_USERNAME environment variable must be specified`)
}
return v
})()
export const CORE_PB_PASSWORD = (() => {
const v = process.env.CORE_PB_PASSWORD
if (!v) {
throw new Error(`CORE_PB_PASSWORD environment variable must be specified`)
}
return v
})()
export const CORE_PB_PORT = process.env.CORE_PB_PORT
? parseInt(process.env.CORE_PB_PORT, 10)
: 8090
export const PB_IDLE_TTL = process.env.PB_IDLE_TTL
? parseInt(process.env.PB_IDLE_TTL, 10)
: 5000

View File

@ -1,78 +0,0 @@
import { pocketbase } from '@pockethost/common/src/pocketbase'
import {
InstanceId,
Instance_Internal_In,
Instance_Internal_Out,
Instance_Internal_Out_ByIdCollection,
InternalInstanceId,
Password,
Port,
Username,
} from '@pockethost/common/src/schema'
import Bottleneck from 'bottleneck'
import { identity } from 'ts-brand'
const limiter = new Bottleneck({ maxConcurrent: 1 })
const client = pocketbase
export const adminAuthViaEmail = (username: Username, password: Password) =>
client.admins.authViaEmail(username, password)
export const getAllInternalInstancesByInstanceId = async () =>
(
await limiter
.schedule(() => client.records.getFullList('instances_internal'))
.catch((e) => {
console.error(`getAllInternalInstancesById failed with ${e}`)
throw e
})
).reduce((c, v) => {
const _v = identity<Instance_Internal_Out>(v)
c[identity<InstanceId>(_v.instanceId)] = _v
return c
}, {} as Instance_Internal_Out_ByIdCollection)
export const setInternalInstancePort = (
instanceId: InternalInstanceId,
port: Port
) =>
limiter
.schedule(() =>
client.records.update('instances_internal', instanceId, { port })
)
.catch((e) => {
console.error(
`setInternalInstancePort failed for ${instanceId} port ${port} with ${e}`
)
throw e
})
export const setInternalInstance = (
instanceId: InternalInstanceId,
fields: Instance_Internal_In
) => {
console.log(`${instanceId} setting fields`, { fields })
return limiter
.schedule(() =>
client.records.update('instances_internal', instanceId, fields)
)
.catch((e) => {
console.error(`setInternalInstance failed for ${instanceId} with ${e}`, {
fields,
})
throw e
})
}
export const linkInternalInstance = async (instanceId: InstanceId) => {
const _in: Instance_Internal_In = {
instanceId,
}
return (await limiter
.schedule(() => client.records.create('instances_internal', _in))
.catch((e) => {
console.error(`linkInternalInstance failed for ${instanceId} with ${e}`)
throw e
})) as unknown as Instance_Internal_Out
}

View File

@ -1,35 +0,0 @@
import { Port, Subdomain } from '@pockethost/common/src/schema'
export const NGINX_TEMPLATE = (subdomain: Subdomain, port: Port) => `
### BEGIN ${subdomain}:${port} ###
server {
listen 443 ssl;
server_name ${subdomain}.pockethost.io;
ssl_certificate /etc/letsencrypt/live/${subdomain}.pockethost.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${subdomain}.pockethost.io/privkey.pem;
access_log /home/pockethost/data/${subdomain}/logs/access.log;
error_log /home/pockethost/data/${subdomain}/logs/error.log;
location / {
proxy_read_timeout 180s;
# WebSocket support
proxy_buffering off; # For realtime
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:${port};
}
}
### END ${subdomain}:${port} ###
`

View File

@ -1,10 +0,0 @@
import { ProcessId } from '@pockethost/common/src/schema'
export function pidIsRunning(pid: ProcessId) {
try {
process.kill(pid, 0)
return true
} catch (e) {
return false
}
}

View File

@ -1,240 +1,2 @@
import { assertExists } from '@pockethost/common/src/assert'
import {
getAllInstancesById,
setInstance,
} from '@pockethost/common/src/pocketbase'
import {
InstanceId,
InstanceStatuses,
Password,
pocketNow,
Port,
ProcessId,
Subdomain,
Username,
} from '@pockethost/common/src/schema'
import { map } from '@s-libs/micro-dash'
import Bottleneck from 'bottleneck'
import { exec, spawn } from 'child_process'
import { mkdir, writeFile } from 'fs'
import getPort from 'get-port'
import { identity } from 'ts-brand'
import util from 'util'
import {
adminAuthViaEmail,
getAllInternalInstancesByInstanceId,
linkInternalInstance,
setInternalInstance,
setInternalInstancePort,
} from './internal'
import { NGINX_TEMPLATE } from './nginx-template'
import { pidIsRunning } from './pidIsRunning'
const pMkdir = util.promisify(mkdir)
const pWriteFile = util.promisify(writeFile)
const pExec = util.promisify(exec)
const singleLimiter = new Bottleneck({ maxConcurrent: 1 })
const HOME_DIR = `/home/pockethost`
const DATA_ROOT = `${HOME_DIR}/data`
spawn(`pocketbase`, [
`serve`,
`--dir`,
`${DATA_ROOT}/pockethost-central/pb_data`,
`--http`,
`127.0.0.1:8090`,
])
;(async () => {
await adminAuthViaEmail(
identity<Username>(`ben@pockethost.io`),
identity<Password>('c6j3ARgcUvut')
)
console.log(`logged in as admin`)
// Subscribe to changes in any record from the "demo" collection
// client.realtime.subscribe('instances', function (e) {
// console.log(`record changed`, e.record)
// })
// alternatively you can also fetch all records at once via getFullList:
const _check = async () => {
console.log(`Fetching current state`)
const [allInstances, allInternalInstances] = await Promise.all([
getAllInstancesById(),
getAllInternalInstancesByInstanceId(),
])
let needsNginx = false
const nginxConfigs: string[] = [
NGINX_TEMPLATE(
identity<Subdomain>(`pockethost-central`),
identity<Port>(8090)
),
]
const provision = (() => {
const instances: InstanceId[] = []
const add = (instanceId: InstanceId, status: InstanceStatuses) => {
if (instances.indexOf(instanceId) < 0) {
instances.push(instanceId) // Track this instance
}
console.log(`${instanceId} status is ${status}`)
return setInstance(instanceId, {
status,
})
}
const finish = () => {
const p = Promise.all(
instances.map((instanceId) =>
setInstance(instanceId, { status: InstanceStatuses.Started })
)
)
instances.length = 0
return p
}
return { add, finish }
})()
await Promise.all(
map(allInstances, async (instance, instanceId) => {
const ROOT_DIR = `${DATA_ROOT}/${instance.subdomain}`
const LOG_DIR = `${ROOT_DIR}/logs`
const DATA_DIR = `${ROOT_DIR}/pb_data`
console.log(`Examining instance ${instanceId}`)
if (!allInternalInstances[instanceId]) {
console.log(`${instanceId} linking internal`)
await provision.add(instanceId, InstanceStatuses.Provisioning)
allInternalInstances[instanceId] = await linkInternalInstance(
instanceId
).catch((e) => {
console.error(`${instanceId} error linking internal`)
throw e
})
console.log(`${instanceId} done linking internal`)
}
const internalInstance = allInternalInstances[instanceId]
assertExists(internalInstance, `Expected instance here`)
if (!internalInstance.port) {
const exclude = map(allInternalInstances, (i) => i.port).filter(
(v) => !!v
)
console.log(`${instanceId} needs port`, exclude)
await provision.add(instanceId, InstanceStatuses.Port)
const newPort = identity<Port>(
await getPort({
port: 8090,
exclude,
}).catch((e) => {
console.error(`Failed to get port`)
throw e
})
)
await setInternalInstancePort(internalInstance.id, newPort)
internalInstance.port = newPort
console.log(`${instanceId} port ${newPort}`)
needsNginx = true
}
if (!internalInstance.certCreatedAt) {
console.log(`${instanceId} needs cert`)
await provision.add(instanceId, InstanceStatuses.Cert)
const CERTBOT_CMD = `certbot certonly --keep --agree-tos --nginx --email pockethost@benallfree.com -d ${instance.subdomain}.pockethost.io`
await singleLimiter
.schedule(() => pExec(CERTBOT_CMD))
.catch((e) => {
console.error(`${instanceId} certbot error: ${e}`)
throw e
})
const certCreatedAt = pocketNow()
await setInternalInstance(internalInstance.id, {
certCreatedAt,
})
internalInstance.certCreatedAt = certCreatedAt
console.log(`${instanceId} cert created at ${certCreatedAt}`)
needsNginx = true
}
await Promise.all([
pMkdir(LOG_DIR, { recursive: true }),
pMkdir(DATA_DIR, { recursive: true }),
])
needsNginx = needsNginx || !internalInstance.nginxCreatedAt
nginxConfigs.push(
NGINX_TEMPLATE(instance.subdomain, internalInstance.port)
)
if (!internalInstance.pid || !pidIsRunning(internalInstance.pid)) {
console.log(`${instanceId} PocketHost instance is not running`)
await provision.add(instanceId, InstanceStatuses.Starting)
const child = spawn(`pocketbase`, [
`serve`,
`--dir`,
DATA_DIR,
`--http`,
`127.0.0.1:${internalInstance.port}`,
])
const { pid } = child
assertExists<ProcessId>(pid, `Expected PID for ${instanceId}`)
const launchedAt = pocketNow()
setInternalInstance(internalInstance.id, {
pid,
launchedAt,
})
internalInstance.pid = pid
internalInstance.launchedAt = launchedAt
console.log(
`${instanceId} PocketHost instance is running on PID ${pid}`
)
}
})
)
if (needsNginx) {
console.log(`NGINX needs a rebuild`)
const configs = nginxConfigs.join(`\n`)
console.log(`NGINX config`)
const NGINX_CONF = `/etc/nginx/sites-enabled/_instances`
await pWriteFile(NGINX_CONF, configs).catch((e) => {
console.error(`Error writing nginx conf: ${e}`)
throw e
})
await pExec(`systemctl reload nginx`)
await Promise.all(
map(allInternalInstances, async (internalInstance) => {
const nginxCreatedAt = pocketNow()
setInternalInstance(internalInstance.id, { nginxCreatedAt })
})
)
}
await provision.finish()
console.log(`Finished with everything, checking again soon`)
}
const _recheck = () => {
setTimeout(
() =>
_check()
.catch((e) => {
console.error(`Check failed: ${e}`)
})
.finally(() => {
setImmediate(_recheck)
}),
1000
)
}
_recheck()
})().catch((e) => {
console.error(`Fatal error`, e)
})
import { createProxyServer } from './ProxyServer'
createProxyServer()

View File

@ -11,7 +11,8 @@
"module": "ESNext",
"moduleResolution": "node",
"noUncheckedIndexedAccess": true,
"strictNullChecks": true
"strictNullChecks": true,
"noEmit": true
},
"ts-node": {
"esm": true

View File

@ -0,0 +1,92 @@
Arguments:
/usr/local/bin/node /Users/meta/.yarn/bin/yarn.js
PATH:
/Users/meta/.yarn/bin:/Users/meta/.config/yarn/global/node_modules/.bin:/Volumes/Code/butler-darwin-amd64:/Users/meta/.bun/bin:/Users/meta/Downloads/google-cloud-sdk/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Library/Apple/usr/bin
Yarn version:
1.22.19
Node version:
18.9.0
Platform:
darwin arm64
Trace:
Error: https://registry.yarnpkg.com/@pockethost%2fcommon: Not found
at params.callback [as _callback] (/Users/meta/.yarn/lib/cli.js:66145:18)
at self.callback (/Users/meta/.yarn/lib/cli.js:140890:22)
at Request.emit (node:events:513:28)
at Request.<anonymous> (/Users/meta/.yarn/lib/cli.js:141862:10)
at Request.emit (node:events:513:28)
at IncomingMessage.<anonymous> (/Users/meta/.yarn/lib/cli.js:141784:12)
at Object.onceWrapper (node:events:627:28)
at IncomingMessage.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
npm manifest:
{
"name": "@pockethost/daemon",
"version": "0.0.1",
"license": "MIT",
"type": "module",
"scripts": {
"build": "parcel",
"watch": "parcel watch",
"serve": "ts-node src/server.ts"
},
"targets": {
"server": {
"engines": {
"node": ">=18"
},
"source": "src/server.ts",
"includeNodeModules": [
"@pockethost/common",
"get-port",
"pocketbase",
"@s-libs/micro-dash"
]
}
},
"dependencies": {
"@pockethost/common": "0.0.1",
"@s-libs/micro-dash": "^14.1.0",
"@types/http-proxy": "^1.17.9",
"bottleneck": "^2.19.5",
"event-source-polyfill": "^1.0.31",
"get-port": "^6.1.2",
"http-proxy": "^1.18.1",
"pocketbase": "^0.7.0",
"ts-node": "^10.9.1"
},
"devDependencies": {
"parcel": "^2.7.0",
"ts-node": "^10.9.1"
}
}
yarn manifest:
No manifest
Lockfile:
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
event-source-polyfill@^1.0.31:
version "1.0.31"
resolved "https://registry.yarnpkg.com/event-source-polyfill/-/event-source-polyfill-1.0.31.tgz#45fb0a6fc1375b2ba597361ba4287ffec5bf2e0c"
integrity sha512-4IJSItgS/41IxN5UVAVuAyczwZF7ZIEsM1XAoUzIHA6A+xzusEZUutdXz2Nr+MQPLxfTiCvqE79/C8HT8fKFvA==
get-port@^6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/get-port/-/get-port-6.1.2.tgz#c1228abb67ba0e17fb346da33b15187833b9c08a"
integrity sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==
pocketbase@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/pocketbase/-/pocketbase-0.7.0.tgz#bfce0225e03321cfa816f589a6dee60ec8b2f726"
integrity sha512-55le5D1dfthouWzxTIkL3eMgEsQqZsdT9O5HWFkCmbw889EKZsz0kf+2kkWgPvZqeVVXfOhMpJNHVOK5L2fJ3A==

View File

@ -2,28 +2,31 @@ module pocketbase
go 1.19
require github.com/pocketbase/pocketbase v0.7.9
require (
github.com/AlecAivazis/survey/v2 v2.3.5 // indirect
github.com/AlecAivazis/survey/v2 v2.3.6 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/aws/aws-sdk-go v1.44.85 // indirect
github.com/aws/aws-sdk-go-v2 v1.16.11 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4 // indirect
github.com/aws/aws-sdk-go-v2/config v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.12.14 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.27 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.13 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.12 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 // indirect
github.com/aws/smithy-go v1.12.1 // indirect
github.com/aws/aws-sdk-go v1.44.102 // indirect
github.com/aws/aws-sdk-go-v2 v1.16.16 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 // indirect
github.com/aws/aws-sdk-go-v2/config v1.17.7 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.12.20 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.16.19 // indirect
github.com/aws/smithy-go v1.13.3 // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/domodwyer/mailyak/v3 v3.3.4 // indirect
github.com/fatih/color v1.13.0 // indirect
@ -45,7 +48,6 @@ require (
github.com/mattn/go-sqlite3 v1.14.15 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/pocketbase/dbx v1.6.0 // indirect
github.com/pocketbase/pocketbase v0.7.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.5.0 // indirect
@ -54,30 +56,30 @@ require (
github.com/valyala/fasttemplate v1.2.1 // indirect
go.opencensus.io v0.23.0 // indirect
gocloud.dev v0.26.0 // indirect
golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 // indirect
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c // indirect
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 // indirect
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 // indirect
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9 // indirect
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
golang.org/x/time v0.0.0-20220920022843-2ce7c2934d45 // indirect
golang.org/x/tools v0.1.12 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/api v0.94.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.96.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 // indirect
google.golang.org/grpc v1.49.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.36.3 // indirect
modernc.org/cc/v3 v3.39.0 // indirect
modernc.org/ccgo/v3 v3.16.9 // indirect
modernc.org/libc v1.17.0 // indirect
modernc.org/libc v1.19.0 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.2.0 // indirect
modernc.org/memory v1.4.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sqlite v1.18.1 // indirect
modernc.org/strutil v1.1.2 // indirect
modernc.org/token v1.0.0 // indirect
modernc.org/sqlite v1.19.1 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)

View File

@ -29,6 +29,7 @@ cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Ud
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8=
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
@ -42,12 +43,14 @@ cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJW
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c=
cloud.google.com/go/iam v0.1.1/go.mod h1:CKqrcnI/suGpybEHxZ7BMehL0oA4LpdyJdUlTl9jVMw=
cloud.google.com/go/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
cloud.google.com/go/kms v1.1.0/go.mod h1:WdbppnCDMDpOvoYBMn1+gNmOeEoZYqAv+HeuKARGCXI=
cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA=
@ -65,6 +68,7 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.21.0/go.mod h1:XmRlxkgPjlBONznT2dDUU/5XlpU2OjMnKuqnZI01LAA=
cloud.google.com/go/storage v1.22.1 h1:F6IlQJZrZM++apn9V5/VfS3gbTUYg98PS3EMQAzqtfg=
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguHpGcr6A=
cloud.google.com/go/trace v1.2.0/go.mod h1:Wc8y/uYyOhPy12KEnXG9XGrvfMz5F5SrYecQlbW1rwM=
@ -72,10 +76,11 @@ contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod
contrib.go.opencensus.io/exporter/stackdriver v0.13.10/go.mod h1:I5htMbyta491eUxufwwZPQdcKvvgzMB4O9ni41YnIM8=
contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AlecAivazis/survey/v2 v2.3.5 h1:A8cYupsAZkjaUmhtTYv3sSqc7LO5mp1XDfqe5E/9wRQ=
github.com/AlecAivazis/survey/v2 v2.3.5/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
github.com/Azure/azure-amqp-common-go/v3 v3.2.1/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI=
github.com/Azure/azure-amqp-common-go/v3 v3.2.2/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI=
github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v59.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@ -83,6 +88,7 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbL
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/Azure/azure-service-bus-go v0.11.5/go.mod h1:MI6ge2CuQWBVq+ly456MY7XqNLJip5LO1iSFodbNLbU=
github.com/Azure/azure-storage-blob-go v0.14.0 h1:1BCg74AmVdYwO3dlKwtFU1V0wU2PZdREkXvAmZJRUlM=
github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck=
github.com/Azure/go-amqp v0.16.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
github.com/Azure/go-amqp v0.16.4/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
@ -106,6 +112,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/GoogleCloudPlatform/cloudsql-proxy v1.29.0/go.mod h1:spvB9eLJH9dutlbPSRmHvSXXHOwGRyeXh1jVdquA2G8=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@ -115,66 +122,68 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:W
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.85 h1:JM2rkKY/GtTDCQXW0StkImbLn6n4Q/Dm2bj+u1rm7Kw=
github.com/aws/aws-sdk-go v1.44.85/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.102 h1:6tUCTGL2UDbFZae1TLGk8vTgeXuzkb8KbAe2FiAeKHc=
github.com/aws/aws-sdk-go v1.44.102/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
github.com/aws/aws-sdk-go-v2 v1.16.11 h1:xM1ZPSvty3xVmdxiGr7ay/wlqv+MWhH0rMlyLdbC0YQ=
github.com/aws/aws-sdk-go-v2 v1.16.11/go.mod h1:WTACcleLz6VZTp7fak4EO5b9Q4foxbn+8PIz3PmyKlo=
github.com/aws/aws-sdk-go-v2 v1.16.16 h1:M1fj4FE2lB4NzRb9Y0xdWsn2P0+2UHVxwKyOa4YJNjk=
github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD2wJ9kCRTczA83gYbBmjSwZp3umc6zF4EeM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4 h1:zfT11pa7ifu/VlLDpmc5OY2W4nYmnKkFDGeMVnmqAI0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4/go.mod h1:ES0I1GBs+YYgcDS1ek47Erbn4TOL811JKqBXtgzqyZ8=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 h1:tcFliCWne+zOuUfKNRn8JdFBuWPDuISDH08wD2ULkhk=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8/go.mod h1:JTnlBSot91steJeti4ryyu/tLd4Sk84O5W22L7O2EQU=
github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg=
github.com/aws/aws-sdk-go-v2/config v1.17.1 h1:BWxTjokU/69BZ4DnLrZco6OvBDii6ToEdfBL/y5I1nA=
github.com/aws/aws-sdk-go-v2/config v1.17.1/go.mod h1:uOxDHjBemNTF2Zos+fgG0NNfE86wn1OAHDTGxjMEYi0=
github.com/aws/aws-sdk-go-v2/config v1.17.7 h1:odVM52tFHhpqZBKNjVW5h+Zt1tKHbhdTQRb+0WHrNtw=
github.com/aws/aws-sdk-go-v2/config v1.17.7/go.mod h1:dN2gja/QXxFF15hQreyrqYhLBaQo1d9ZKe/v/uplQoI=
github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g=
github.com/aws/aws-sdk-go-v2/credentials v1.12.14 h1:AtVG/amkjbDBfnPr/tuW2IG18HGNznP6L12Dx0rLz+Q=
github.com/aws/aws-sdk-go-v2/credentials v1.12.14/go.mod h1:opAndTyq+YN7IpVG57z2CeNuXSQMqTYxGGlYH0m0RMY=
github.com/aws/aws-sdk-go-v2/credentials v1.12.20 h1:9+ZhlDY7N9dPnUmf7CDfW9In4sW5Ff3bh7oy4DzS1IE=
github.com/aws/aws-sdk-go-v2/credentials v1.12.20/go.mod h1:UKY5HyIux08bbNA7Blv4PcXQ8cTkGh7ghHMFklaviR4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 h1:wgJBHO58Pc1V1QAnzdVM3JK3WbE/6eUF0JxCZ+/izz0=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12/go.mod h1:aZ4vZnyUuxedC7eD4JyEHpGnCz+O2sHQEx3VvAwklSE=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17 h1:r08j4sbZu/RVi+BNxkBJwPMUYY3P8mgSDuKkZ/ZN1lE=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17/go.mod h1:yIkQcCDYNsZfXpd5UX2Cy+sWA1jPgIhGTw9cOBzfVnQ=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.27 h1:xFXIMBci0UXStoOHq/8w0XIZPB2hgb9CD7uATJhqt10=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.27/go.mod h1:+tj2cHQkChanggNZn1J2fJ1Cv6RO1TV0AA3472do31I=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33 h1:fAoVmNGhir6BR+RU0/EI+6+D7abM+MCwWf8v4ip5jNI=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33/go.mod h1:84XgODVR8uRhmOnUkKGUZKqIMxmjmLOR8Uyp7G/TPwc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 h1:OmiwoVyLKEqqD5GvB683dbSqxiOfvx4U2lDZhG2Esc4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18/go.mod h1:348MLhzV1GSlZSMusdwQpXKbhD7X2gbI/TxwAPKkYZQ=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 h1:s4g/wnzMf+qepSNgTvaQQHNxyMLKSawNhKCPNy++2xY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12 h1:5mvQDtNWtI6H56+E4LUnLWEmATMB7oEh+Z9RurtIuC0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12/go.mod h1:ckaCVTEdGAxO6KwTGzgskxR1xM+iJW4lxMyDFVda2Fc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 h1:/K482T5A3623WJgWT8w1yRAFK4RzGzEl7y39yhtn9eA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10/go.mod h1:8DcYQcz0+ZJaSxANlHIsbbi6S+zMwjwdDqwW3r9AzaE=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19 h1:g5qq9sgtEzt2szMaDqQO6fqKe026T6dHTFJp5NsPzkQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19/go.mod h1:cVHo8KTuHjShb9V8/VjH3S/8+xPu16qx8fdGwmotJhE=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.9 h1:agLpf3vtYX1rtKTrOGpevdP3iC2W0hKDmzmhhxJzL+A=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.9/go.mod h1:cv+n1mdyh+0B8tAtlEBzTYFA2Uv15SISEn6kabYhIgE=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 h1:wj5Rwc05hvUSvKuOF29IYb9QrCLjU+rHAy/x/o0DK2c=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24/go.mod h1:jULHjqqjDlbyTa7pfM7WICATnOv+iOhjletM3N0Xbu8=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14 h1:ZSIPAkAsCCjYrhqfw2+lNzWDzxzHXEckFkTePL5RSWQ=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14/go.mod h1:AyGgqiKv9ECM6IZeNQtdT8NnMvUb3/2wokeq2Fgryto=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.5 h1:g1ITJ9i9ixa+/WVggLNK20KyliAA8ltnuxfZEDfo2hM=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.5/go.mod h1:oehQLbMQkppKLXvpx/1Eo0X47Fe+0971DXC9UjGnKcI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9 h1:Lh1AShsuIJTwMkoxVCAYPJgNG5H+eN6SmoUn8nOZ5wE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9/go.mod h1:a9j48l6yL5XINLHLcOKInjdvknN+vWqPBxqeIDw7ktw=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.3/go.mod h1:Seb8KNmD6kVTjwRjVEgOT5hPin6sq+v4C2ycJQDwuH8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.13 h1:3GamN8jcdz/a3nvL/ZVtoH/6xxeshfsiXj5O+6GW4Rg=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.13/go.mod h1:89CSPn69UECDLVn0H6FwKNgbtirksl8C8i3aBeeeihw=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18 h1:BBYoNQt2kUZUUK4bIPsKrCcjVPUMNsgQpNAwhznK/zo=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18/go.mod h1:NS55eQ4YixUJPTC+INxi2/jCqe1y2Uw3rnh9wEOVJxY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3/go.mod h1:wlY6SVjuwvh3TVRpTqdy4I1JpBFLX4UGeKZdWntaocw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12 h1:7iPTTX4SAI2U2VOogD7/gmHlsgnYSgoNHt7MSQXtG2M=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12/go.mod h1:1TODGhheLWjpQWSuhYuAUWYTCKwEjx2iblIFKDHjeTc=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3/go.mod h1:Bm/v2IaN6rZ+Op7zX+bOUMdL4fsrYZiD0dsjLhNKwZc=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.12 h1:QFjSOmHSb77qRTv7KI9UFon9X5wLWY5/M+6la3dTcZc=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.12/go.mod h1:MADjAN0GHFDuc5lRa5Y5ki+oIO/w7X4qczHy+OUx0IA=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 h1:HfVVR1vItaG6le+Bpw6P4midjBDMKnjMyZnw9MXYUcE=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17/go.mod h1:YqMdV+gEKCQ59NrB7rzrJdALeBIsYiVi8Inj3+KcqHI=
github.com/aws/aws-sdk-go-v2/service/kms v1.16.3/go.mod h1:QuiHPBqlOFCi4LqdSskYYAWpQlx3PKmohy+rE2F+o5g=
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3/go.mod h1:g1qvDuRsJY+XghsV6zg00Z4KJ7DtFFCx8fJD2a491Ak=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.5 h1:h9qqTedYnA9JcWjKyLV6UYIMSdp91ExLCUbjbpDLH7A=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.5/go.mod h1:J8SS5Tp/zeLxaubB0xGfKnVrvssNBNLwTipreTKLhjQ=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11/go.mod h1:fmgDANqTUCxciViKl9hb/zD5LFbvPINFRgWhDbR+vZo=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.4/go.mod h1:PJc8s+lxyU8rrre0/4a0pn2wgwiDvOEzoOjcJUBr67o=
github.com/aws/aws-sdk-go-v2/service/sns v1.17.4/go.mod h1:kElt+uCcXxcqFyc+bQqZPFD9DME/eC6oHBXvFzQ9Bcw=
github.com/aws/aws-sdk-go-v2/service/sqs v1.18.3/go.mod h1:skmQo0UPvsjsuYYSYMVmrPc1HWCbHUJyrCEp+ZaLzqM=
github.com/aws/aws-sdk-go-v2/service/ssm v1.24.1/go.mod h1:NR/xoKjdbRJ+qx0pMR4mI+N/H1I1ynHwXnO6FowXJc0=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.17 h1:pXxu9u2z1UqSbjO9YA8kmFJBhFc1EVTDaf7A+S+Ivq8=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.17/go.mod h1:mS5xqLZc/6kc06IpXn5vRxdLaED+jEuaSRv5BxtnsiY=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 h1:pwvCchFUEnlceKIgPUouBJwK81aCkQ8UDMORfeFtW10=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.23/go.mod h1:/w0eg9IhFGjGyyncHIQrXtU8wvNsTJOP0R6PPj0wf80=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.5 h1:GUnZ62TevLqIoDyHeiWj2P7EqaosgakBKVvWriIdLQY=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.5/go.mod h1:csZuQY65DAdFBt1oIjO5hhBR49kQqop4+lcuCjf2arA=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 h1:dl8T0PJlN92rvEGOEUiD0+YPYdPEaCZK0TqHukvSfII=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13/go.mod h1:Ru3QVMLygVs/07UQ3YDur1AQZZp2tUNje8wfloFttC0=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.19 h1:9pPi0PsFNAGILFfPCk8Y0iyEBGc6lu6OQ97U7hmdesg=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.19/go.mod h1:h4J3oPZQbxLhzGnk+j9dfYHi5qIOVJ5kczZd658/ydM=
github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
github.com/aws/smithy-go v1.12.1 h1:yQRC55aXN/y1W10HgwHle01DRuV9Dpf31iGkotjt3Ag=
github.com/aws/smithy-go v1.12.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA=
github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -199,8 +208,10 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU=
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
@ -211,6 +222,7 @@ github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44am
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/domodwyer/mailyak/v3 v3.3.4 h1:AG/pvcz2/ocFqZkPEG7lPAa0MhCq1warfUEKJt6Fagk=
github.com/domodwyer/mailyak/v3 v3.3.4/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -226,6 +238,7 @@ github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q=
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
@ -249,6 +262,7 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
@ -311,15 +325,20 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE=
github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk=
github.com/google/go-replayers/httpreplay v1.1.1 h1:H91sIMlt1NZzN7R+/ASswyouLJfW0WLW7fhyUFvDEkY=
github.com/google/go-replayers/httpreplay v1.1.1/go.mod h1:gN9GeLIs7l6NUoVaSSnv2RiqK1NiwAmD0MrKeC9IIks=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible h1:xmapqc1AyLoB+ddYT6r04bD9lIjlOqGaREovi0SzFaE=
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -345,6 +364,7 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.1.0 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw=
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@ -355,6 +375,7 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
github.com/googleapis/gax-go/v2 v2.5.1 h1:kBRZU0PSuI7PspsSb/ChWoVResUcwNVIdpB049pKTiw=
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
@ -362,6 +383,7 @@ github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFi
github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@ -409,6 +431,7 @@ github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -423,9 +446,11 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198 h1:lFz33AOOXwTpqOiHvrN8nmTdkxSfuNLHLPjgQ1muPpU=
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198/go.mod h1:uh3YlzsEJj7OG57rDWj6c3WEkOF1ZHGBQkDuUZw3rE8=
@ -441,6 +466,7 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@ -463,16 +489,18 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pocketbase/dbx v1.6.0 h1:iPQi99GpaMRne0KRVnd/kCfxayCP/f4QDb6hGxMRI3I=
github.com/pocketbase/dbx v1.6.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
github.com/pocketbase/pocketbase v0.7.2 h1:lvrzls6YKRFv7YDwrWPa8bzy4qNkIlXRcf8KOG+ic3E=
github.com/pocketbase/pocketbase v0.7.2/go.mod h1:xg/tpAOX3hUlAeSnkmgH7Tmx76ESNynLrHsUZ48drxA=
github.com/pocketbase/pocketbase v0.7.9 h1:UKYTazbzHu5ziq4itDYgtiZIWu99cahTpPnQbgVr3qY=
github.com/pocketbase/pocketbase v0.7.9/go.mod h1:KR0kEXd5CrR0qiwnRafWwQpjuCtxIR6LNgHcopFxbJk=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
@ -497,6 +525,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
@ -554,8 +583,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 h1:vJ2V3lFLg+bBhgroYuRfyN583UzVveQmIXjc8T/y3to=
golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -569,8 +598,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU=
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -645,8 +674,9 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c h1:JVAXQ10yGGVbSyoer5VILysz6YKjdNT2bsvlayjqhes=
golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9 h1:SdDGdqRuKrF2R4XGcnPzcvZ63c/55GvhoHUus0o+BNI=
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -669,8 +699,9 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA=
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -758,16 +789,16 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220919170432-7a66f970e087 h1:tPwmk4vmvVCMdr98VgL4JH+qZxPL8fqlUOHnyOM8N3w=
golang.org/x/term v0.0.0-20220919170432-7a66f970e087/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -783,8 +814,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220920022843-2ce7c2934d45 h1:yuLAip3bfURHClMG9VBdzPrQvCWjWiWUTBGV+/fCbUs=
golang.org/x/time v0.0.0-20220920022843-2ce7c2934d45/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -853,8 +884,9 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@ -901,8 +933,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
google.golang.org/api v0.94.0 h1:KtKM9ru3nzQioV1HLlUf1cR7vMYJIpgls5VhAYQXIwA=
google.golang.org/api v0.94.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
google.golang.org/api v0.96.0 h1:F60cuQPJq7K7FzsxMYHAUJSiXh2oKctHxBMbDygxhfM=
google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1005,8 +1037,8 @@ google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc h1:Nf+EdcTLHR8qDNN/KfkQL0u0ssxt9OhbaWCl5C0ucEI=
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 h1:mmbq5q8M1t7dhkLw320YK4PsOXm6jdnUAkErImaIqOg=
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -1065,8 +1097,10 @@ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:a
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@ -1079,30 +1113,37 @@ lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg=
modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.39.0 h1:sd+UyMj63acEV1jaFqxFGPQfllSncJgL+roJjFlo6lI=
modernc.org/cc/v3 v3.39.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM=
modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.17.0 h1:nbL2Lv0I323wLc1GmTh/AqVtI9JeBVc7Nhapdg9EONs=
modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0=
modernc.org/libc v1.19.0 h1:bXyVhGQg6KIClTr8FMVIDPl7jtbcs7aS5WP7vLDaxPs=
modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.2.0 h1:zXehBrt9n+Pjn+4RoRCZ0KqRA/0ePFqcecxZ/hXCIVw=
modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8=
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
modernc.org/sqlite v1.19.1 h1:8xmS5oLnZtAK//vnd4aTVj8VOeTAccEFOtUnIzfSw+4=
modernc.org/sqlite v1.19.1/go.mod h1:UfQ83woKMaPW/ZBruK0T7YaFCrI+IE0LeWVY6pmnVms=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/strutil v1.1.2 h1:iFBDH6j1Z0bN/Q9udJnnFoFpENA4252qe/7/5woE5MI=
modernc.org/strutil v1.1.2/go.mod h1:OYajnUAcI/MX+XD/Wx7v1bbdvcQSvxgtb0gC+u3d3eg=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.14.0 h1:cO7oyRWEXweSJmjdbs1L86P52D9QmBy/CPFKmFvNYTU=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.6.0 h1:gLwAw6aS973K/k9EOJGlofauyMk4YOUiPDYzWnq/oXo=
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

View File

@ -0,0 +1,8 @@
{
"name": "enchanted-pocketbase",
"version": "0.0.1",
"license": "MIT",
"scripts": {
"build": "GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build"
}
}

View File

@ -10,11 +10,13 @@
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check .",
"format": "prettier --write .",
"serve": "node dist-server/index.js"
"serve": "node dist-server/index.js",
"watch": "chokidar 'src/**' -c 'yarn build' --initial"
},
"devDependencies": {
"@sveltejs/adapter-auto": "next",
"@sveltejs/kit": "next",
"chokidar-cli": "^3.0.0",
"svelte": "^3.44.0",
"svelte-check": "^2.7.1",
"svelte-preprocess": "^4.10.6",
@ -34,7 +36,6 @@
"sass": "^1.54.9",
"svelte-fa": "^3.0.3",
"svelte-highlight": "^6.2.1",
"sveltestrap": "^5.9.0",
"ts-brand": "^0.0.2"
"sveltestrap": "^5.9.0"
}
}

View File

@ -4,7 +4,7 @@
declare namespace App {
// interface Locals {}
// interface PageData {}
// interface PageError {}
// interface Error {}
// interface Platform {}
}

View File

@ -1,16 +0,0 @@
import { map } from '@s-libs/micro-dash'
import { ClientResponseError } from 'pocketbase'
export const parseError = (e) => {
if (e instanceof ClientResponseError) {
const { data } = e
if (!data || !data.data) {
return `Unknown error ${e.message}`
}
return map(data.data, (v, k) => (v ? v.message : undefined))
.filter((v) => !!v)
.join('<br/>')
} else {
return `Unknown error ${e.message}`
}
}

View File

@ -1,6 +1,6 @@
<script lang="ts">
import { client } from '$src/pocketbase'
import { redirect } from '$util/redirect'
import { isLoggedIn, logOut, user } from '@pockethost/common/src/pocketbase'
import {
Collapse,
Dropdown,
@ -28,6 +28,8 @@
isOpen = event.detail.valueOf()
}
const { isLoggedIn, logOut, user } = client
const handleLogout = () => {
logOut()
redirect(`/`)

View File

@ -1,7 +1,9 @@
<script lang="ts">
import { browser } from '$app/environment'
import { client } from '$src/pocketbase'
import { redirect } from '$util/redirect'
import { isLoggedIn } from '@pockethost/common/src/pocketbase'
const { isLoggedIn } = client
if (browser && !isLoggedIn()) {
redirect(`/signup`)

View File

@ -1,32 +1,32 @@
<script lang="ts">
import { InstanceStatuses } from '@pockethost/common/src/schema'
import { ProvisioningSize } from './types'
import { InstanceStatus } from '@pockethost/common/src/schema'
import { ProvisioningSize } from './types'
export let status: InstanceStatuses = InstanceStatuses.Unknown
export let size: ProvisioningSize = ProvisioningSize.Normal
export let status: InstanceStatus = InstanceStatus.Unknown
export let size: ProvisioningSize = ProvisioningSize.Normal
</script>
<div class={`status ${status} ${size}`}>{status}</div>
<style lang="scss">
.status {
border-radius: 5px;
display: inline-block;
padding: 3px;
font-size: 10px;
background-color: rgb(217, 138, 10);
color: white;
&.started {
background-color: green;
}
&.failed {
background-color: red;
}
&.hero {
font-size: 50px;
padding: 20px;
border-radius: 20px;
border: 1px solid black;
}
}
.status {
border-radius: 5px;
display: inline-block;
padding: 3px;
font-size: 10px;
background-color: rgb(217, 138, 10);
color: white;
&.started {
background-color: green;
}
&.failed {
background-color: red;
}
&.hero {
font-size: 50px;
padding: 20px;
border-radius: 20px;
border: 1px solid black;
}
}
</style>

View File

@ -0,0 +1,7 @@
import { PUBLIC_APP_DOMAIN, PUBLIC_CORE_PB_SUBDOMAIN } from '$env/static/public'
import { createPocketbaseClient } from '@pockethost/common'
const url = `https://${PUBLIC_CORE_PB_SUBDOMAIN}.${PUBLIC_APP_DOMAIN}`
const client = createPocketbaseClient(url)
export { client }

View File

@ -5,6 +5,7 @@
import { CaptionSize } from '$components/Caption/types'
import Feature from '$components/Feature.svelte'
import Gap from '$components/Gap.svelte'
import { PUBLIC_APP_DOMAIN } from '$env/static/public'
</script>
<main>
@ -42,7 +43,8 @@
</Feature>
<Feature title={'Auth'}
>Email and oAuth authentication options work out of the box. Send transactional email to your
users from our verified domain and your custom address, <code>yoursubdomin@pockethost.io</code
users from our verified domain and your custom address, <code
>yoursubdomin@{PUBLIC_APP_DOMAIN}</code
>.</Feature
>
<Feature title={'Storage'}

View File

@ -7,42 +7,41 @@
import ProvisioningStatus from '$components/ProvisioningStatus/ProvisioningStatus.svelte'
import { ProvisioningSize } from '$components/ProvisioningStatus/types'
import Title from '$components/Title/Title.svelte'
import { PUBLIC_APP_DOMAIN } from '$env/static/public'
import { client } from '$src/pocketbase'
import { assertExists } from '@pockethost/common/src/assert'
import { watchInstanceById } from '@pockethost/common/src/pocketbase'
import {
InstanceStatuses,
type InstanceId,
type Instance_Out
} from '@pockethost/common/src/schema'
import { InstanceStatus, type Instance_Out } from '@pockethost/common/src/schema'
import { onDestroy, onMount } from 'svelte'
import type { Unsubscriber } from 'svelte/store'
import { identity } from 'ts-brand'
const { instanceId } = $page.params
let instance: Instance_Out | undefined
const { watchInstanceById } = client
let url: string
let code: string = ''
let unsub: Unsubscriber = () => {}
onMount(() => {
unsub = watchInstanceById(identity<InstanceId>(instanceId), (r) => {
unsub = watchInstanceById(instanceId, (r) => {
console.log(`got a record`, r)
instance = r
assertExists(instance, `Expected instance here`)
const { subdomain } = instance
url = `https://${subdomain}.pockethost.io`
url = `https://${subdomain}.${PUBLIC_APP_DOMAIN}`
code = `const url = '${url}'\nconst client = new PocketBase(url)`
})
})
onDestroy(() => unsub())
const isRunning = (instance: Instance_Out) =>
instance.status === InstanceStatus.Running || instance.status === InstanceStatus.Idle
</script>
<Protected>
<main>
<Title />
{#if instance}
{#if instance.status === InstanceStatuses.Started}
{#if isRunning(instance)}
<ProvisioningStatus status={instance.status} />
<div>
@ -53,7 +52,7 @@
<CodeSample {code} />
</div>
{/if}
{#if instance.status !== InstanceStatuses.Started}
{#if !isRunning}
<Caption>Please stand by, your instance is starting now...</Caption>
<div class="provisioning">
<ProvisioningStatus status={instance.status} size={ProvisioningSize.Hero} />

View File

@ -3,29 +3,28 @@
import Button from '$components/Button/Button.svelte'
import { ButtonColors, ButtonSizes } from '$components/Button/types'
import Error from '$components/Error/Error.svelte'
import { parseError } from '$components/Error/parseError'
import Protected from '$components/Protected.svelte'
import Title from '$components/Title/Title.svelte'
import { PUBLIC_APP_DOMAIN } from '$env/static/public'
import { client } from '$src/pocketbase'
import { redirect } from '$util/redirect'
import { faRefresh } from '@fortawesome/free-solid-svg-icons'
import { assertExists } from '@pockethost/common/src/assert'
import { createInstance, user } from '@pockethost/common/src/pocketbase'
import type { Subdomain, UserId } from '@pockethost/common/src/schema'
import PocketBase from 'pocketbase'
import type { UserId } from '@pockethost/common/src/schema'
import { generateSlug } from 'random-word-slugs'
import Fa from 'svelte-fa'
import { identity } from 'ts-brand'
const client = new PocketBase('https://db.pockethost.io')
if (browser && !client.authStore.isValid) {
const { user, createInstance, parseError } = client
if (browser && !user) {
redirect('/signup')
}
let instanceName = generateSlug(2)
let errorMessage = ''
let errorMessage: string[] = []
let code = ''
$: {
code = `const url = 'https://${instanceName}.pockethost.io'\nconst client = new PocketBase(url)`
code = `const url = 'https://${instanceName}.${PUBLIC_APP_DOMAIN}'\nconst client = new PocketBase(url)`
}
const handleCreate = () => {
@ -33,7 +32,7 @@
const { id } = user() || {}
assertExists<UserId>(id, `Expected uid here`)
createInstance({
subdomain: identity<Subdomain>(instanceName),
subdomain: instanceName,
uid: id
})
.then((rec) => {
@ -42,7 +41,7 @@
})
.catch((e) => {
errorMessage = parseError(e)
console.error(errorMessage, e)
console.error(errorMessage.join('\n'), e)
})
}
</script>
@ -62,9 +61,9 @@
name="instanceName"
type="text"
bind:value={instanceName}
/>.pockethost.io
/>.{PUBLIC_APP_DOMAIN}
</div>
<Error>{errorMessage}</Error>
<Error>{errorMessage.join('<br/>')}</Error>
<Button click={handleCreate}>Create</Button>
<Button href={`/dashboard`} color={ButtonColors.Light}>Cancel</Button>
</main>

View File

@ -5,19 +5,44 @@
import Protected from '$components/Protected.svelte'
import ProvisioningStatus from '$components/ProvisioningStatus/ProvisioningStatus.svelte'
import Title from '$components/Title/Title.svelte'
import { getAllInstancesById } from '@pockethost/common/src/pocketbase'
import { InstanceStatuses, type Instance_Out_ByIdCollection } from '@pockethost/common/src/schema'
import { values } from '@s-libs/micro-dash'
import { PUBLIC_APP_DOMAIN } from '$env/static/public'
import { client } from '$src/pocketbase'
import {
InstanceStatus,
type Instance_Out,
type Instance_Out_ByIdCollection
} from '@pockethost/common/src/schema'
import { forEach, values } from '@s-libs/micro-dash'
import { onDestroy, onMount } from 'svelte'
import type { Unsubscriber } from 'svelte/store'
import { Col, Container, Row } from 'sveltestrap'
const { getAllInstancesById, watchInstanceById } = client
let apps: Instance_Out_ByIdCollection = {}
getAllInstancesById()
.then((instances) => {
apps = instances
})
.catch((e) => {
console.error(`Failed to fetch instances`)
})
const isRunning = (app: Instance_Out) =>
app.status === InstanceStatus.Running || app.status === InstanceStatus.Idle
let unsubs: Unsubscriber[] = []
onMount(() => {
getAllInstancesById()
.then((instances) => {
apps = instances
forEach(apps, (app) => {
const instanceId = app.id
const unsub = watchInstanceById(instanceId, (r) => {
console.log(`got a record`, r)
apps[r.id] = r
})
unsubs.push(unsub)
})
})
.catch((e) => {
console.error(`Failed to fetch instances`)
})
})
onDestroy(() => {
unsubs.forEach((u) => u())
})
</script>
<Protected>
@ -31,17 +56,17 @@
<ProvisioningStatus status={app.status} />
</Col>
<Col>
{app.subdomain}.pockethost.io
{app.subdomain}.{PUBLIC_APP_DOMAIN}
</Col>
<Col>
<Button size={ButtonSizes.Micro} href={`/app/instances/${app.id}`}>Details</Button>
<Button
disabled={app.status !== InstanceStatuses.Started}
disabled={!isRunning(app)}
size={ButtonSizes.Micro}
click={() => {
window.open(`https://${app.subdomain}.pockethost.io/_`)
window.open(`https://${app.subdomain}.${PUBLIC_APP_DOMAIN}/_`)
}}>Admin</Button
>
</Col>

View File

@ -1,14 +1,16 @@
<script lang="ts">
import Button from '$components/Button/Button.svelte'
import Title from '$components/Title/Title.svelte'
import { client } from '$src/pocketbase'
import { redirect } from '$util/redirect'
import { authViaEmail } from '@pockethost/common/src/pocketbase'
import { Form, FormGroup, Input, Label } from 'sveltestrap'
let email = ''
let password = ''
let loginError = ''
const { authViaEmail } = client
const handleLogin = () => {
loginError = ''
authViaEmail(email, password)

View File

@ -0,0 +1,31 @@
<script lang="ts">
import Title from '$components/Title/Title.svelte'
import { TitleSize } from '$components/Title/types'
</script>
<Title first="So" second="Much" third="Quiet" size={TitleSize.Normal} />
<main>
<img src="https://media4.giphy.com/media/V9sdMLcmIFqqk/giphy.gif?cid=790b76118f409453704f5eaabaea1a3dc7380a9daf4fca63&rid=giphy.gif&ct=g"/>
<h3>The PocketHost instance you are seeking does not exist.</h3>
<p>Please check the instance URL and try again.</p>
</main>
<style type="text/scss">
main {
max-width: 600px;
margin-left: auto;
margin-right: auto;
img {
width: 100%
}
.caption {
font-size: 30px;
margin-top: 20px;
margin-bottom: 20px;
}
}
</style>

View File

@ -1,15 +1,15 @@
<script lang="ts">
import Button from '$components/Button/Button.svelte'
import Error from '$components/Error/Error.svelte'
import { parseError } from '$components/Error/parseError'
import Title from '$components/Title/Title.svelte'
import { TitleSize } from '$components/Title/types'
import { client } from '$src/pocketbase'
import { redirect } from '$util/redirect'
import { authViaEmail, createUser } from '@pockethost/common/src/pocketbase'
import { Form, FormGroup, Input, Label } from 'sveltestrap'
const { authViaEmail, createUser, parseError } = client
let email = ''
let emailError = ''
let emailError: string[] = []
let password = ''
let passwordError = ''
@ -22,7 +22,7 @@
// .catch((e) => console.error(`user login error`, e))
const handleSignup = () => {
emailError = ''
emailError = []
passwordError = ''
createUser(email, password)
.then((user) => {
@ -37,7 +37,7 @@
})
.catch((e) => {
emailError = parseError(e)
console.error(emailError, e)
console.error(emailError.join('\n'), e)
})
}
</script>
@ -49,7 +49,7 @@
<FormGroup>
<Label for="email">Email Address</Label>
<Input type="email" bind:value={email} id="email" />
<Error>{emailError}</Error>
<Error>{emailError.join('<br/>')}</Error>
</FormGroup>
<FormGroup>
<Label for="password">Password</Label>

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,6 @@
# PocketHost
# pockethost.io
This is the open source monorepo for PocketHost.
PocketHost is a zero-config backend (database, authentication, functions, and storage) meant to rival Firebase and Supabase. Spin up your own fully managed backend for your next app at [https://pockethost.io](https://pockethost.io).
This is the open source monorepo for pockethost.io, the hosting platform for PocketBase.
Get up and running in 30 seconds flat:
@ -22,21 +20,34 @@ const client = new PocketBase(`https://harvest.pockethost.io`)
PocketBase is very, very cool. But, to run and manage it successfully, you need to know a lot of backend Linux sysadmin/devops stuff:
- VPS
- Probably Docker
- Email and DKIM+SPF and more
- DNS, MX, TXT, CNAME
- SSL
- Storage
- Volume mounts
- Could computing or VPS
That's where PocketHost comes in. Firebase and Supabase have made BaaS very attrictive, and PocketHost brings that same attractiveness to PocketBase.
## Roadmap
- Tighter integration with PocketBase
- Cloud functions in Node or Deno
- Cloud functions [PBScript](https://github.com/benallfree/pbscript)
- Lightstream support
- fly.io deployment support
## Questions?
Join us in the discussion area.
## Changelog
### 0.2.0
- 100% dockerized
- Completley rewritten daemon proxy that launches PocketBase instances on demand
### 0.0.1
- Initial release

856
yarn.lock

File diff suppressed because it is too large Load Diff