mirror of
https://github.com/pockethost/pockethost.git
synced 2025-03-30 15:08:30 +00:00
Initial public commit
This commit is contained in:
commit
27961edd90
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
.secret
|
5
.rsyncignore
Normal file
5
.rsyncignore
Normal file
@ -0,0 +1,5 @@
|
||||
.git
|
||||
node_modules
|
||||
.svelte-kit
|
||||
*.log
|
||||
attic
|
26
attic/Dockerfile-alpine
Normal file
26
attic/Dockerfile-alpine
Normal file
@ -0,0 +1,26 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
|
||||
RUN apk update
|
||||
RUN apk add -v build-base
|
||||
RUN apk add -v go
|
||||
RUN apk add -v ca-certificates
|
||||
RUN apk add -v git
|
||||
|
||||
COPY ./pocketbase /pocketbase
|
||||
WORKDIR /pocketbase
|
||||
RUN go clean
|
||||
RUN go build
|
||||
RUN chmod +x pocketbase
|
||||
RUN mv pocketbase /usr/local/bin/pocketbase
|
||||
WORKDIR /
|
||||
|
||||
ADD ./data /data
|
||||
ADD ./nginx/conf.d /etc/nginx/conf.d
|
||||
|
||||
# Notify Docker that the container wants to expose a port.
|
||||
EXPOSE 80
|
||||
|
||||
COPY ./run.sh /run.sh
|
||||
RUN chmod +x /run.sh
|
||||
ENTRYPOINT ./run.sh
|
37
attic/Dockerfile-fly
Normal file
37
attic/Dockerfile-fly
Normal file
@ -0,0 +1,37 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
# RUN apk add openrc
|
||||
# RUN apt update
|
||||
# RUN apt-get install -y unzip
|
||||
# RUN apt-get install -y nginx
|
||||
# RUN apt-get install -y systemd
|
||||
RUN apk add -v build-base
|
||||
RUN apk add -v go
|
||||
RUN apk add -v ca-certificates
|
||||
|
||||
|
||||
|
||||
# COPY ./pockethost-init.d /etc/init.d/pockethost
|
||||
# RUN chmod +x /etc/init.d/pockethost
|
||||
# RUN service nginx start
|
||||
# RUN service pockethost start
|
||||
|
||||
COPY ./run.sh /run.sh
|
||||
RUN chmod +x /run.sh
|
||||
|
||||
COPY ./pockethost /pockethost
|
||||
WORKDIR /pockethost
|
||||
RUN ls
|
||||
RUN go clean
|
||||
RUN go build
|
||||
RUN chmod +x pockethost
|
||||
RUN mv pockethost /usr/local/bin/pockethost
|
||||
WORKDIR /
|
||||
|
||||
ADD ./data /data
|
||||
ADD ./nginx/conf.d /etc/nginx/conf.d
|
||||
|
||||
# Notify Docker that the container wants to expose a port.
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT /run.sh
|
23
attic/Dockerfile-nginx
Normal file
23
attic/Dockerfile-nginx
Normal file
@ -0,0 +1,23 @@
|
||||
FROM nginx:latest
|
||||
|
||||
ARG POCKETBASE_VERSION=0.7.2
|
||||
|
||||
RUN apt update
|
||||
RUN apt install -y unzip systemd systemd-sysv
|
||||
RUN apt install -y systemd
|
||||
RUN apt install -y systemd-sysv
|
||||
|
||||
# Download Pocketbase and install it for AMD64
|
||||
ADD https://github.com/pocketbase/pocketbase/releases/download/v${POCKETBASE_VERSION}/pocketbase_${POCKETBASE_VERSION}_linux_amd64.zip /tmp/pocketbase.zip
|
||||
RUN unzip /tmp/pocketbase.zip -d /usr/local/bin/
|
||||
RUN chmod +x /usr/local/bin/pocketbase
|
||||
|
||||
ADD ./data /data
|
||||
ADD ./nginx/conf.d /etc/nginx/conf.d
|
||||
|
||||
COPY ./pockethost-db.service /etc/systemd/system/pockethost-db.service
|
||||
RUN systemctl enable pockethost-db.service
|
||||
# RUN echo "::respawn:/usr/local/bin/pocketbase serve --http '127.0.0.1:8090' --dir /data/pockethost" >> /etc/inittab
|
||||
|
||||
# Notify Docker that the container wants to expose a port.
|
||||
EXPOSE 80
|
22
attic/Dockerfile-raw
Normal file
22
attic/Dockerfile-raw
Normal file
@ -0,0 +1,22 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
|
||||
RUN apk update
|
||||
RUN apk add -v build-base
|
||||
RUN apk add -v go
|
||||
RUN apk add -v ca-certificates
|
||||
RUN apk add -v git
|
||||
|
||||
COPY ./pocketbase /pocketbase
|
||||
WORKDIR /pocketbase
|
||||
RUN go clean
|
||||
RUN go build
|
||||
RUN chmod +x pocketbase
|
||||
RUN mv pocketbase /usr/local/bin/pocketbase
|
||||
WORKDIR /
|
||||
|
||||
|
||||
# Notify Docker that the container wants to expose a port.
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT pocketbase serve --http 127.0.0.1:80
|
19
attic/Dockerfile-ubuntu
Normal file
19
attic/Dockerfile-ubuntu
Normal file
@ -0,0 +1,19 @@
|
||||
FROM ubuntu
|
||||
|
||||
RUN apt update
|
||||
RUN apt-get install -y golang-go
|
||||
RUN apt-get install -y ca-certificates
|
||||
|
||||
COPY ./pocketbase /pocketbase
|
||||
WORKDIR /pocketbase
|
||||
RUN go clean
|
||||
RUN go build
|
||||
RUN chmod +x pocketbase
|
||||
RUN mv pocketbase /usr/local/bin/pocketbase
|
||||
WORKDIR /
|
||||
|
||||
ADD ./data /data
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT ["tail", "-f", "/dev/null"]
|
2
attic/build-server.sh
Normal file
2
attic/build-server.sh
Normal file
@ -0,0 +1,2 @@
|
||||
apt up
|
||||
apt upgrade -y
|
6
attic/build.sh
Executable file
6
attic/build.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker container rm -f pockethost
|
||||
docker image rm -f pockethost
|
||||
docker build -f $1 -t pockethost .
|
||||
docker run --name pockethost -p 80:80 pockethost
|
38
attic/fly.toml
Normal file
38
attic/fly.toml
Normal file
@ -0,0 +1,38 @@
|
||||
# fly.toml file generated for pockethost on 2022-09-15T20:05:31-07:00
|
||||
|
||||
app = "pockethost"
|
||||
kill_signal = "SIGINT"
|
||||
kill_timeout = 5
|
||||
processes = []
|
||||
|
||||
[env]
|
||||
|
||||
[experimental]
|
||||
allowed_public_ports = []
|
||||
auto_rollback = true
|
||||
|
||||
[[services]]
|
||||
http_checks = []
|
||||
internal_port = 8090
|
||||
processes = ["app"]
|
||||
protocol = "tcp"
|
||||
script_checks = []
|
||||
[services.concurrency]
|
||||
hard_limit = 25
|
||||
soft_limit = 20
|
||||
type = "connections"
|
||||
|
||||
[[services.ports]]
|
||||
force_https = true
|
||||
handlers = ["http"]
|
||||
port = 80
|
||||
|
||||
[[services.ports]]
|
||||
handlers = ["tls", "http"]
|
||||
port = 443
|
||||
|
||||
[[services.tcp_checks]]
|
||||
grace_period = "1s"
|
||||
interval = "15s"
|
||||
restart_limit = 0
|
||||
timeout = "2s"
|
53
attic/nginx/conf.d/app.conf
Normal file
53
attic/nginx/conf.d/app.conf
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name db.*;
|
||||
|
||||
access_log /data/nginx/access.log main;
|
||||
error_log /data/nginx/error.log;
|
||||
|
||||
location / {
|
||||
# check http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive
|
||||
proxy_set_header Connection '';
|
||||
proxy_http_version 1.1;
|
||||
proxy_read_timeout 180s;
|
||||
|
||||
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:8090;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name www.*;
|
||||
|
||||
access_log /data/nginx/access.log main;
|
||||
error_log /data/nginx/error.log;
|
||||
|
||||
location / {
|
||||
root /data/pockethost_html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
#error_page 404 /404.html;
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
#
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /data/pockethost_html;
|
||||
}
|
||||
|
||||
# deny access to .htaccess files, if Apache's document root
|
||||
# concurs with nginx's one
|
||||
#
|
||||
#location ~ /\.ht {
|
||||
# deny all;
|
||||
#}
|
||||
}
|
||||
|
16
attic/nginx/force_ssl.conf
Normal file
16
attic/nginx/force_ssl.conf
Normal file
@ -0,0 +1,16 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.org;
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name example.org;
|
||||
|
||||
location / {
|
||||
proxy_pass http://example.org; #for demo purposes
|
||||
}
|
||||
}
|
32
attic/nginx/nginx.conf
Normal file
32
attic/nginx/nginx.conf
Normal file
@ -0,0 +1,32 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
|
16
attic/pockethost-db.service
Normal file
16
attic/pockethost-db.service
Normal file
@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Pockethost DB Service
|
||||
|
||||
[Service]
|
||||
StandardOutput = append:/data/pockethost/logs/errors.log
|
||||
StandardError = append:/data/pockethost/logs/errors.log
|
||||
ExecStart=/usr/local/bin/pockethost serve --http '127.0.0.1:8090' --dir /data/pockethost
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
|
||||
[Unit]
|
||||
Description = pocketbase
|
||||
|
23
attic/pockethost-init.d
Normal file
23
attic/pockethost-init.d
Normal file
@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: pockethost
|
||||
# Short-Description: starts the pockethost db server
|
||||
# Description: starts the pockethost db server
|
||||
### END INIT INFO
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
NAME=pockethost
|
||||
DESC=pockethost
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting $DESC" "$NAME"
|
||||
pockethost serve --http '127.0.0.1:8090' --dir /data/pockethost &
|
||||
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping $DESC" "$NAME"
|
||||
|
||||
esac
|
11
attic/pockethost-init.d-openrc
Normal file
11
attic/pockethost-init.d-openrc
Normal file
@ -0,0 +1,11 @@
|
||||
#!/sbin/openrc-run
|
||||
|
||||
description="Pockethost server"
|
||||
extra_commands=""
|
||||
extra_started_commands=""
|
||||
|
||||
|
||||
start_pre() {
|
||||
einfo "Starting pockethost"
|
||||
/usr/local/bin/pocketbase serve --http '127.0.0.1:8090' --dir /data/pockethost
|
||||
}
|
1
attic/pockethost/.gitignore
vendored
Normal file
1
attic/pockethost/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
pockethost
|
83
attic/pockethost/go.mod
Normal file
83
attic/pockethost/go.mod
Normal file
@ -0,0 +1,83 @@
|
||||
module pockethost
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.5 // 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/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/domodwyer/mailyak/v3 v3.3.4 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
|
||||
github.com/ganigeorgiev/fexpr v0.1.1 // indirect
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/wire v0.5.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.5.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
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
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
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/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/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // 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
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // 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/ccgo/v3 v3.16.9 // indirect
|
||||
modernc.org/libc v1.17.0 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.2.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
|
||||
)
|
1109
attic/pockethost/go.sum
Normal file
1109
attic/pockethost/go.sum
Normal file
File diff suppressed because it is too large
Load Diff
15
attic/pockethost/pockethost.go
Normal file
15
attic/pockethost/pockethost.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/pocketbase/pocketbase"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := pocketbase.New()
|
||||
|
||||
if err := app.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
4
attic/run.sh
Normal file
4
attic/run.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
nginx
|
||||
pocketbase serve
|
32
package.json
Normal file
32
package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "pockethost",
|
||||
"version": "0.0.1",
|
||||
"main": "index.js",
|
||||
"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/fcs-client",
|
||||
"packages/worker",
|
||||
"packages/admin",
|
||||
"packages/*"
|
||||
],
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"plugins": [
|
||||
"./node_modules/prettier-plugin-organize-imports",
|
||||
"./node_modules/prettier-plugin-svelte"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.7.1",
|
||||
"prettier-plugin-organize-imports": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^2.7.0",
|
||||
"typescript": "^4.8.3"
|
||||
}
|
||||
}
|
11
packages/common/package.json
Normal file
11
packages/common/package.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@pockethost/common",
|
||||
"version": "0.0.1",
|
||||
"main": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^4.0.0",
|
||||
"pocketbase": "^0.7.0",
|
||||
"ts-brand": "^0.0.2"
|
||||
}
|
||||
}
|
29
packages/common/src/RealtimeSubscriptionManager.ts
Normal file
29
packages/common/src/RealtimeSubscriptionManager.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { pocketbase } from './pocketbase'
|
||||
import { Any_Record_Out } from './schema'
|
||||
|
||||
export const createRealtimeSubscriptionManager = () => {
|
||||
const subscriptions: { [_: string]: number } = {}
|
||||
|
||||
const subscribe = <TRec extends Any_Record_Out>(
|
||||
slug: string,
|
||||
cb: (rec: TRec) => void
|
||||
) => {
|
||||
if (subscriptions[slug]) {
|
||||
subscriptions[slug]++
|
||||
} else {
|
||||
subscriptions[slug] = 1
|
||||
pocketbase.realtime.subscribe(slug, (e) => {
|
||||
console.log(`Realtime update`, { e })
|
||||
cb(e.record as unknown as TRec)
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
subscriptions[slug]--
|
||||
if (subscriptions[slug] === 0) {
|
||||
pocketbase.realtime.unsubscribe(slug)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return subscribe
|
||||
}
|
8
packages/common/src/assert.ts
Normal file
8
packages/common/src/assert.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export function assertExists<TType>(
|
||||
v: unknown,
|
||||
message = `Value does not exist`
|
||||
): asserts v is NonNullable<TType> {
|
||||
if (typeof v === 'undefined') {
|
||||
throw new Error(message)
|
||||
}
|
||||
}
|
1
packages/common/src/isBrowser.ts
Normal file
1
packages/common/src/isBrowser.ts
Normal file
@ -0,0 +1 @@
|
||||
export const isBrowser = () => typeof window !== 'undefined'
|
87
packages/common/src/pocketbase.ts
Normal file
87
packages/common/src/pocketbase.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import pocketbaseEs, { BaseAuthStore } 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'
|
||||
|
||||
const client = new pocketbaseEs('https://pockethost-central.pockethost.io')
|
||||
|
||||
const { authStore } = client
|
||||
|
||||
const { onChange } = authStore
|
||||
|
||||
export const user = () => authStore.model
|
||||
|
||||
export const isLoggedIn = () => authStore.isValid
|
||||
|
||||
export const onAuthChange = (cb: (user: BaseAuthStore) => Unsubscriber) =>
|
||||
onChange(() => cb(authStore))
|
||||
|
||||
export const logOut = () => authStore.clear()
|
||||
|
||||
export 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)
|
||||
|
||||
export const pocketbase = client
|
||||
|
||||
export const createInstance = (payload: Instance_In): Promise<Instance_Out> => {
|
||||
return pocketbase.records
|
||||
.create('instances', payload)
|
||||
.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()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
export const getAllInstancesById = async () =>
|
||||
(
|
||||
await client.records.getFullList('instances').catch((e) => {
|
||||
console.error(`getAllInstancesById failed with ${e}`)
|
||||
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
|
||||
})
|
||||
}
|
69
packages/common/src/schema.ts
Normal file
69
packages/common/src/schema.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { AnyBrand, Brand, identity } from 'ts-brand'
|
||||
|
||||
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 = () => identity<IsoDate>(new Date().toISOString())
|
||||
|
||||
export enum InstanceStatuses {
|
||||
Unknown = '',
|
||||
Provisioning = 'provisioning',
|
||||
Port = 'obtaining port',
|
||||
Cert = 'creating SSL cert',
|
||||
Starting = 'starting',
|
||||
Started = 'started',
|
||||
Failed = 'failed',
|
||||
}
|
||||
|
||||
export type Instance_In = {
|
||||
uid?: UserId
|
||||
subdomain?: Subdomain
|
||||
status?: InstanceStatuses
|
||||
}
|
||||
|
||||
export type PocketbaseRecord<TIdType extends AnyBrand> = {
|
||||
id: TIdType
|
||||
created: IsoDate
|
||||
updated: IsoDate
|
||||
}
|
||||
|
||||
export type Instance_Out = PocketbaseRecord<InstanceId> & {
|
||||
uid: UserId
|
||||
subdomain: Subdomain
|
||||
status: InstanceStatuses
|
||||
}
|
||||
|
||||
export type Instance_Internal_In = {
|
||||
instanceId?: InstanceId
|
||||
port?: Port
|
||||
certCreatedAt?: IsoDate
|
||||
nginxCreatedAt?: IsoDate
|
||||
pid?: ProcessId
|
||||
launchedAt?: IsoDate
|
||||
}
|
||||
|
||||
export type Instance_Internal_Out = PocketbaseRecord<InternalInstanceId> & {
|
||||
instanceId: InstanceId
|
||||
port: Port
|
||||
certCreatedAt: IsoDate
|
||||
nginxCreatedAt: IsoDate
|
||||
pid: ProcessId
|
||||
launchedAt: IsoDate
|
||||
}
|
||||
|
||||
export type Any_Record_Out = Instance_Out | Instance_Internal_Out
|
||||
|
||||
export type Instance_Out_ByIdCollection = {
|
||||
[_: InstanceId]: Instance_Out
|
||||
}
|
||||
|
||||
export type Instance_Internal_Out_ByIdCollection = {
|
||||
[_: InstanceId]: Instance_Internal_Out
|
||||
}
|
2
packages/daemon/.gitignore
vendored
Normal file
2
packages/daemon/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.parcel-cache
|
||||
dist
|
36
packages/daemon/package.json
Normal file
36
packages/daemon/package.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "@pockethost/daemon",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "parcel",
|
||||
"serve": "node dist/server.js"
|
||||
},
|
||||
"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",
|
||||
"bottleneck": "^2.19.5",
|
||||
"event-source-polyfill": "^1.0.31",
|
||||
"get-port": "^6.1.2",
|
||||
"pocketbase": "^0.7.0",
|
||||
"ts-brand": "^0.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"parcel": "^2.7.0",
|
||||
"ts-node": "^10.9.1"
|
||||
}
|
||||
}
|
10
packages/daemon/samples/add.sh
Normal file
10
packages/daemon/samples/add.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
PORT=8090
|
||||
SUBDOMAIN=db
|
||||
|
||||
sudo certbot certonly --agree-tos --nginx --email pockethost@benallfree.com -d $SUBDOMAIN.pockethost.io
|
||||
|
||||
NGINX_CONFIG=envsubst < nginx-template.conf
|
||||
|
||||
echo $NGINX_CONFIG
|
1
packages/daemon/samples/certbot
Normal file
1
packages/daemon/samples/certbot
Normal file
@ -0,0 +1 @@
|
||||
sudo certbot certonly --agree-tos --nginx --email pockethost@benallfree.com -d $SUBDOMAIN.pockethost.io
|
1
packages/daemon/samples/launch
Normal file
1
packages/daemon/samples/launch
Normal file
@ -0,0 +1 @@
|
||||
pocketbase serve --dir ~/pocketbase-microservice/data/$SUBDOMAIN/pb_data --http 127.0.0.1:$PORT &
|
28
packages/daemon/samples/nginx-template.conf
Normal file
28
packages/daemon/samples/nginx-template.conf
Normal file
@ -0,0 +1,28 @@
|
||||
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/pockethost-microservice/data/$SUBDOMAIN/logs/access.log;
|
||||
error_log /home/pockethost/pockethost-microservice/data/$SUBDOMAIN/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://127.0.0.1:$PORT;
|
||||
}
|
||||
}
|
||||
|
||||
|
78
packages/daemon/src/internal.ts
Normal file
78
packages/daemon/src/internal.ts
Normal file
@ -0,0 +1,78 @@
|
||||
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
|
||||
}
|
35
packages/daemon/src/nginx-template.ts
Normal file
35
packages/daemon/src/nginx-template.ts
Normal file
@ -0,0 +1,35 @@
|
||||
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} ###
|
||||
|
||||
`
|
10
packages/daemon/src/pidIsRunning.ts
Normal file
10
packages/daemon/src/pidIsRunning.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { ProcessId } from '@pockethost/common/src/schema'
|
||||
|
||||
export function pidIsRunning(pid: ProcessId) {
|
||||
try {
|
||||
process.kill(pid, 0)
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
240
packages/daemon/src/server.ts
Normal file
240
packages/daemon/src/server.ts
Normal file
@ -0,0 +1,240 @@
|
||||
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)
|
||||
})
|
20
packages/daemon/tsconfig.json
Normal file
20
packages/daemon/tsconfig.json
Normal 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
|
||||
},
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
18
packages/daemon/yarn.lock
Normal file
18
packages/daemon/yarn.lock
Normal file
@ -0,0 +1,18 @@
|
||||
# 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==
|
1
packages/pocketbase/.gitignore
vendored
Normal file
1
packages/pocketbase/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
pocketbase
|
83
packages/pocketbase/go.mod
Normal file
83
packages/pocketbase/go.mod
Normal file
@ -0,0 +1,83 @@
|
||||
module pocketbase
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.5 // 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/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/domodwyer/mailyak/v3 v3.3.4 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
|
||||
github.com/ganigeorgiev/fexpr v0.1.1 // indirect
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/wire v0.5.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.5.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
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
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
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/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/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // 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
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // 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/ccgo/v3 v3.16.9 // indirect
|
||||
modernc.org/libc v1.17.0 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.2.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
|
||||
)
|
1109
packages/pocketbase/go.sum
Normal file
1109
packages/pocketbase/go.sum
Normal file
File diff suppressed because it is too large
Load Diff
15
packages/pocketbase/pocketbase.go
Normal file
15
packages/pocketbase/pocketbase.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/pocketbase/pocketbase"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := pocketbase.New()
|
||||
|
||||
if err := app.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
9
packages/pockethost.io/.gitignore
vendored
Normal file
9
packages/pockethost.io/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
dist-server
|
1
packages/pockethost.io/.npmrc
Normal file
1
packages/pockethost.io/.npmrc
Normal file
@ -0,0 +1 @@
|
||||
engine-strict=true
|
13
packages/pockethost.io/.prettierignore
Normal file
13
packages/pockethost.io/.prettierignore
Normal file
@ -0,0 +1,13 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
19
packages/pockethost.io/.prettierrc
Normal file
19
packages/pockethost.io/.prettierrc
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"semi": false,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"pluginSearchDirs": [
|
||||
".",
|
||||
"../.."
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": {
|
||||
"parser": "svelte"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
38
packages/pockethost.io/README.md
Normal file
38
packages/pockethost.io/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
# create-svelte
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
39
packages/pockethost.io/package.json
Normal file
39
packages/pockethost.io/package.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@pockethost/app",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check .",
|
||||
"format": "prettier --write .",
|
||||
"serve": "node dist-server/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "next",
|
||||
"@sveltejs/kit": "next",
|
||||
"svelte": "^3.44.0",
|
||||
"svelte-check": "^2.7.1",
|
||||
"svelte-preprocess": "^4.10.6",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^3.1.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.0",
|
||||
"@pockethost/common": "0.0.1",
|
||||
"@s-libs/micro-dash": "12",
|
||||
"@sveltejs/adapter-node": "^1.0.0-next.92",
|
||||
"pocketbase": "^0.7.0",
|
||||
"random-word-slugs": "^0.1.6",
|
||||
"sass": "^1.54.9",
|
||||
"svelte-fa": "^3.0.3",
|
||||
"svelte-highlight": "^6.2.1",
|
||||
"ts-brand": "^0.0.2"
|
||||
}
|
||||
}
|
13
packages/pockethost.io/src/app.d.ts
vendored
Normal file
13
packages/pockethost.io/src/app.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
// and what to do when importing types
|
||||
declare namespace App {
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageError {}
|
||||
// interface Platform {}
|
||||
}
|
||||
|
||||
declare module '@fortawesome/pro-solid-svg-icons/index.es' {
|
||||
export * from '@fortawesome/pro-solid-svg-icons'
|
||||
}
|
13
packages/pockethost.io/src/app.html
Normal file
13
packages/pockethost.io/src/app.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<link rel="stylesheet" href="%sveltekit.assets%/global.css" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
10
packages/pockethost.io/src/components/AuthCheck.svelte
Normal file
10
packages/pockethost.io/src/components/AuthCheck.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { isLoggedIn, user } from '@pockethost/common/src/pocketbase'
|
||||
import Button from './Button/Button.svelte'
|
||||
|
||||
if (typeof window !== 'undefined' && isLoggedIn()) {
|
||||
window.location.href = '/dashboard'
|
||||
}
|
||||
</script>
|
||||
|
||||
<slot />
|
50
packages/pockethost.io/src/components/Button/Button.svelte
Normal file
50
packages/pockethost.io/src/components/Button/Button.svelte
Normal file
@ -0,0 +1,50 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation'
|
||||
import { ButtonStyles } from './types'
|
||||
|
||||
export let style: ButtonStyles = ButtonStyles.Wide
|
||||
export let disabled = false
|
||||
export let href: string = '#'
|
||||
export let click: () => void = () => {
|
||||
goto(href)
|
||||
}
|
||||
</script>
|
||||
|
||||
<button class={style} {disabled} on:click={click}> <slot /></button>
|
||||
|
||||
<style type="text/scss">
|
||||
button,
|
||||
.button {
|
||||
min-width: 100px;
|
||||
width: 100px;
|
||||
white-space: nowrap;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
background: rgb(10, 10, 120);
|
||||
display: inline-block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 10px;
|
||||
font-size: 30px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
&:disabled {
|
||||
background: rgb(64, 64, 107);
|
||||
color: lightgray;
|
||||
}
|
||||
&.wide {
|
||||
width: 100%;
|
||||
}
|
||||
&.micro {
|
||||
width: initial;
|
||||
padding: 2px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
min-width: initial;
|
||||
max-width: initial;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
5
packages/pockethost.io/src/components/Button/types.ts
Normal file
5
packages/pockethost.io/src/components/Button/types.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export enum ButtonStyles {
|
||||
Micro = 'micro',
|
||||
Normal = 'normal',
|
||||
Wide = 'wide',
|
||||
}
|
30
packages/pockethost.io/src/components/Caption/Caption.svelte
Normal file
30
packages/pockethost.io/src/components/Caption/Caption.svelte
Normal file
@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import { CaptionSize } from "./types"
|
||||
|
||||
|
||||
export let size:CaptionSize=CaptionSize.Normal
|
||||
</script>
|
||||
<div class="caption {size}"><slot /></div>
|
||||
|
||||
<style lang="scss">
|
||||
.caption {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
&.small {
|
||||
font-size: 15px;
|
||||
|
||||
}
|
||||
&.normal {
|
||||
font-size: 25px;
|
||||
|
||||
}
|
||||
&.large {
|
||||
font-size: 45px;
|
||||
|
||||
}
|
||||
&.hero {
|
||||
font-size: 65px;
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
6
packages/pockethost.io/src/components/Caption/types.ts
Normal file
6
packages/pockethost.io/src/components/Caption/types.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum CaptionSize {
|
||||
Small='small',
|
||||
Normal='normal',
|
||||
Large='large',
|
||||
Hero='hero'
|
||||
}
|
35
packages/pockethost.io/src/components/Clipboard.svelte
Normal file
35
packages/pockethost.io/src/components/Clipboard.svelte
Normal file
@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { onMount, tick, createEventDispatcher } from 'svelte'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let text: string
|
||||
|
||||
let textarea: HTMLTextAreaElement
|
||||
|
||||
async function copy() {
|
||||
textarea.select()
|
||||
document.execCommand('Copy')
|
||||
await tick()
|
||||
textarea.blur()
|
||||
dispatch('copy')
|
||||
}
|
||||
</script>
|
||||
|
||||
<slot {copy} />
|
||||
<textarea bind:this={textarea} value={text} />
|
||||
|
||||
<style>
|
||||
textarea {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
opacity: 0;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border: none;
|
||||
display: block;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
35
packages/pockethost.io/src/components/CodeSample.svelte
Normal file
35
packages/pockethost.io/src/components/CodeSample.svelte
Normal file
@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
import { typescript } from 'svelte-highlight/languages'
|
||||
import Clipboard from './Clipboard.svelte'
|
||||
import 'svelte-highlight/styles/github.css'
|
||||
import Button from './Button/Button.svelte'
|
||||
import { ButtonStyles } from './Button/types'
|
||||
import CopyButton from './CopyButton.svelte'
|
||||
|
||||
export let code: string
|
||||
const handleCopy = () => {
|
||||
console.log('copied')
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="copy-container">
|
||||
<Highlight language={typescript} {code} />
|
||||
<div class="copy-button">
|
||||
<CopyButton {code} copy={handleCopy} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/scss">
|
||||
.copy-container {
|
||||
position: relative;
|
||||
margin: 5px;
|
||||
border: 1px solid gray;
|
||||
|
||||
.copy-button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
17
packages/pockethost.io/src/components/CopyButton.svelte
Normal file
17
packages/pockethost.io/src/components/CopyButton.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import Button from './Button/Button.svelte'
|
||||
import { ButtonStyles } from './Button/types'
|
||||
import Clipboard from './Clipboard.svelte'
|
||||
|
||||
let isCopied = false
|
||||
export let code: string
|
||||
export let copy: () => void
|
||||
const handleCopy = () => {
|
||||
isCopied = true
|
||||
copy()
|
||||
}
|
||||
</script>
|
||||
|
||||
<Clipboard text={code} let:copy on:copy={handleCopy}>
|
||||
<Button style={ButtonStyles.Micro} click={copy}>{isCopied ? 'Copied!' : 'Copy'}</Button>
|
||||
</Clipboard>
|
8
packages/pockethost.io/src/components/Error/Error.svelte
Normal file
8
packages/pockethost.io/src/components/Error/Error.svelte
Normal file
@ -0,0 +1,8 @@
|
||||
<error><slot /></error>
|
||||
|
||||
<style type="text/scss">
|
||||
error {
|
||||
color: red;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
16
packages/pockethost.io/src/components/Error/parseError.ts
Normal file
16
packages/pockethost.io/src/components/Error/parseError.ts
Normal file
@ -0,0 +1,16 @@
|
||||
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}`
|
||||
}
|
||||
}
|
1
packages/pockethost.io/src/components/Error/types.ts
Normal file
1
packages/pockethost.io/src/components/Error/types.ts
Normal file
@ -0,0 +1 @@
|
||||
export type ErrorMessage = string[] | string
|
31
packages/pockethost.io/src/components/Protected.svelte
Normal file
31
packages/pockethost.io/src/components/Protected.svelte
Normal file
@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { isLoggedIn, logOut, user } from '@pockethost/common/src/pocketbase'
|
||||
import Button from './Button/Button.svelte'
|
||||
import { ButtonStyles } from './Button/types'
|
||||
|
||||
if (typeof window !== 'undefined' && !isLoggedIn()) {
|
||||
window.location.href = '/signup'
|
||||
}
|
||||
|
||||
const handleLogout = () => {
|
||||
logOut()
|
||||
window.location.href = '/'
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="logbar">
|
||||
{user()?.email}
|
||||
<Button style={ButtonStyles.Micro} click={handleLogout}>Log Out</Button>
|
||||
<div>
|
||||
<a href="/dashboard">dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
<slot />
|
||||
|
||||
<style lang="scss">
|
||||
.logbar {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,32 @@
|
||||
<script lang="ts">
|
||||
import { InstanceStatuses } from '@pockethost/common/src/schema'
|
||||
import { ProvisioningSize } from './types'
|
||||
|
||||
export let status: InstanceStatuses = InstanceStatuses.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;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,6 @@
|
||||
export enum ProvisioningSize {
|
||||
Small = 'small',
|
||||
Normal = 'normal',
|
||||
Large = 'large',
|
||||
Hero = 'hero'
|
||||
}
|
22
packages/pockethost.io/src/components/Title.svelte
Normal file
22
packages/pockethost.io/src/components/Title.svelte
Normal file
@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
export let first = 'Pocket'
|
||||
export let second = 'Host'
|
||||
export let third = ''
|
||||
</script>
|
||||
|
||||
<h1>{first}<span id="host">{second}</span>{third}</h1>
|
||||
|
||||
<style type="text/scss">
|
||||
h1 {
|
||||
color: #ff3e00;
|
||||
font-size: 12vw;
|
||||
font-weight: 100;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
text-align: center;
|
||||
#host {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
</style>
|
27
packages/pockethost.io/src/routes/+page.svelte
Normal file
27
packages/pockethost.io/src/routes/+page.svelte
Normal file
@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import Title from '../components/Title.svelte'
|
||||
import Button from '../components/Button/Button.svelte'
|
||||
import AuthCheck from '../components/AuthCheck.svelte'
|
||||
import Caption from '../components/Caption/Caption.svelte'
|
||||
import { CaptionSize } from '../components/Caption/types'
|
||||
</script>
|
||||
|
||||
<AuthCheck>
|
||||
<Title third=".io" />
|
||||
<main>
|
||||
<Caption size={CaptionSize.Hero}>
|
||||
The zero config, zero setup <a href="https://pocketbase.io">PocketBase</a>
|
||||
backend for your next app.
|
||||
</Caption>
|
||||
<Button href="/signup">Get Started</Button>
|
||||
</main>
|
||||
</AuthCheck>
|
||||
|
||||
<style type="text/scss">
|
||||
main {
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,67 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores'
|
||||
import { identity } from 'ts-brand'
|
||||
import Caption from '../../../../components/Caption/Caption.svelte'
|
||||
import CodeSample from '../../../../components/CodeSample.svelte'
|
||||
import Protected from '../../../../components/Protected.svelte'
|
||||
import Title from '../../../../components/Title.svelte'
|
||||
import { isBrowser } from '@pockethost/common/src/isBrowser'
|
||||
import { assertExists } from '@pockethost/common/src/assert'
|
||||
import { getInstanceById, watchInstanceById } from '@pockethost/common/src/pocketbase'
|
||||
import {
|
||||
InstanceStatuses,
|
||||
type InstanceId,
|
||||
type Instance_Out
|
||||
} from '@pockethost/common/src/schema'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
import type { Unsubscriber } from 'svelte/store'
|
||||
import ProvisioningStatus from '../../../../components/ProvisioningStatus/ProvisioningStatus.svelte'
|
||||
import { ProvisioningSize } from '../../../../components/ProvisioningStatus/types'
|
||||
|
||||
const { instanceId } = $page.params
|
||||
|
||||
let instance: Instance_Out | undefined
|
||||
|
||||
let url: string
|
||||
let code: string = ''
|
||||
let unsub: Unsubscriber = () => {}
|
||||
onMount(() => {
|
||||
unsub = watchInstanceById(identity<InstanceId>(instanceId), (r) => {
|
||||
console.log(`got a record`, r)
|
||||
instance = r
|
||||
assertExists(instance, `Expected instance here`)
|
||||
const { subdomain } = instance
|
||||
url = `https://${subdomain}.pockethost.io`
|
||||
code = `const url = '${url}'\nconst client = new PocketBase(url)`
|
||||
})
|
||||
})
|
||||
onDestroy(() => unsub())
|
||||
</script>
|
||||
|
||||
<Protected>
|
||||
<Title />
|
||||
{#if instance}
|
||||
{#if instance.status === InstanceStatuses.Started}
|
||||
<Caption>Your PocketHost instance is now live.</Caption>
|
||||
<div>
|
||||
Admin URL: <a href={`${url}/_`} target="_blank">{`${url}/_`}</a>
|
||||
</div>
|
||||
<div>
|
||||
JavaScript:
|
||||
<CodeSample {code} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if instance.status !== InstanceStatuses.Started}
|
||||
<Caption>Please stand by, your instance is starting now...</Caption>
|
||||
<div class="provisioning">
|
||||
<ProvisioningStatus status={instance.status} size={ProvisioningSize.Hero} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</Protected>
|
||||
|
||||
<style lang="scss">
|
||||
.provisioning {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
95
packages/pockethost.io/src/routes/app/new/+page.svelte
Normal file
95
packages/pockethost.io/src/routes/app/new/+page.svelte
Normal file
@ -0,0 +1,95 @@
|
||||
<script lang="ts">
|
||||
import { faRefresh } from '@fortawesome/free-solid-svg-icons'
|
||||
import PocketBase from 'pocketbase'
|
||||
import { generateSlug } from 'random-word-slugs'
|
||||
import Fa from 'svelte-fa/src/fa.svelte'
|
||||
import Button from '../../../components/Button/Button.svelte'
|
||||
import { ButtonStyles } 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.svelte'
|
||||
import { createInstance, user } from '@pockethost/common/src/pocketbase'
|
||||
import { redirect } from '../../../util/redirect'
|
||||
import { identity } from 'ts-brand'
|
||||
import { assertExists } from '@pockethost/common/src/assert'
|
||||
import type { Subdomain, UserId } from '@pockethost/common/src/schema'
|
||||
|
||||
const client = new PocketBase('https://db.pockethost.io')
|
||||
if (!client.authStore.isValid && typeof window !== 'undefined') {
|
||||
window.location.href = '/signup'
|
||||
}
|
||||
let instanceName = generateSlug(2)
|
||||
|
||||
let errorMessage = ''
|
||||
let code = ''
|
||||
$: {
|
||||
code = `const url = 'https://${instanceName}.pockethost.io'\nconst client = new PocketBase(url)`
|
||||
}
|
||||
|
||||
const handleCreate = () => {
|
||||
console.log(`creating `, instanceName)
|
||||
const { id } = user() || {}
|
||||
assertExists<UserId>(id, `Expected uid here`)
|
||||
createInstance({
|
||||
subdomain: identity<Subdomain>(instanceName),
|
||||
uid: id
|
||||
})
|
||||
.then((rec) => {
|
||||
console.log(`Record`, rec)
|
||||
redirect(`/app/instances/${rec.id}`)
|
||||
})
|
||||
.catch((e) => {
|
||||
errorMessage = parseError(e)
|
||||
console.error(errorMessage, e)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<Protected>
|
||||
<Title />
|
||||
<main>
|
||||
<h2>New App</h2>
|
||||
<div class="caption">Choose a name for your PocketBase app.</div>
|
||||
<div class="subdomain">
|
||||
<label for="instanceName">Instance Name</label>
|
||||
<Button click={() => (instanceName = generateSlug(2))} style={ButtonStyles.Micro}>
|
||||
<Fa icon={faRefresh} /></Button
|
||||
>
|
||||
|
||||
<input
|
||||
class="subdomain"
|
||||
name="instanceName"
|
||||
type="text"
|
||||
bind:value={instanceName}
|
||||
/>.pockethost.io
|
||||
</div>
|
||||
<Error>{errorMessage}</Error>
|
||||
<Button click={handleCreate}>Create</Button>
|
||||
</main>
|
||||
</Protected>
|
||||
|
||||
<style type="text/scss">
|
||||
main {
|
||||
padding: 1em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
}
|
||||
.caption {
|
||||
font-size: 15px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.subdomain {
|
||||
input {
|
||||
text-align: right;
|
||||
max-width: 200px;
|
||||
}
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
</style>
|
57
packages/pockethost.io/src/routes/dashboard/+page.svelte
Normal file
57
packages/pockethost.io/src/routes/dashboard/+page.svelte
Normal file
@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
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 Button from '../../components/Button/Button.svelte'
|
||||
import { ButtonStyles } from '../../components/Button/types'
|
||||
import Protected from '../../components/Protected.svelte'
|
||||
import Title from '../../components/Title.svelte'
|
||||
import ProvisioningStatus from '../../components/ProvisioningStatus/ProvisioningStatus.svelte'
|
||||
|
||||
let apps: Instance_Out_ByIdCollection = {}
|
||||
getAllInstancesById()
|
||||
.then((instances) => {
|
||||
apps = instances
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(`Failed to fetch instances`)
|
||||
})
|
||||
</script>
|
||||
|
||||
<Protected>
|
||||
<Title />
|
||||
<main>
|
||||
<h2>Dashboard</h2>
|
||||
<h4>Apps</h4>
|
||||
{#each values(apps) as app}
|
||||
<div>
|
||||
<ProvisioningStatus status={app.status} />
|
||||
{app.subdomain}.pockethost.io
|
||||
|
||||
<Button style={ButtonStyles.Micro} href={`/app/instances/${app.id}`}>Details</Button>
|
||||
<Button
|
||||
disabled={app.status !== InstanceStatuses.Started}
|
||||
style={ButtonStyles.Micro}
|
||||
click={() => {
|
||||
window.open(`https://${app.subdomain}.pockethost.io/_`)
|
||||
}}>Admin</Button
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
<Button href="/app/new">+</Button>
|
||||
</main>
|
||||
</Protected>
|
||||
|
||||
<style type="text/scss">
|
||||
main {
|
||||
padding: 1em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
.caption {
|
||||
font-size: 30px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
65
packages/pockethost.io/src/routes/login/+page.svelte
Normal file
65
packages/pockethost.io/src/routes/login/+page.svelte
Normal file
@ -0,0 +1,65 @@
|
||||
<script lang="ts">
|
||||
import { ClientResponseError } from 'pocketbase'
|
||||
import AuthCheck from '../../components/AuthCheck.svelte'
|
||||
import Button from '../../components/Button/Button.svelte'
|
||||
import Title from '../../components/Title.svelte'
|
||||
import { authViaEmail, createUser } from '@pockethost/common/src/pocketbase'
|
||||
|
||||
let email = ''
|
||||
let password = ''
|
||||
let loginError = ''
|
||||
|
||||
const handleLogin = () => {
|
||||
loginError = ''
|
||||
authViaEmail(email, password)
|
||||
.then((user) => {
|
||||
console.log(user)
|
||||
window.location.href = '/dashboard'
|
||||
})
|
||||
.catch((e) => {
|
||||
loginError = e.message
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<Title first="Log" second="In" />
|
||||
|
||||
<main>
|
||||
<error>{loginError}</error>
|
||||
<div>
|
||||
<label for="email">Email</label>
|
||||
<input name="email" type="email" bind:value={email} />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password</label>
|
||||
<input name="password" type="password" bind:value={password} />
|
||||
</div>
|
||||
<div>
|
||||
Need to <a href="/signup">create an account</a>?
|
||||
</div>
|
||||
<Button click={handleLogin} disabled={email.length === 0 || password.length === 0}>Log In</Button>
|
||||
</main>
|
||||
|
||||
<style type="text/scss">
|
||||
error {
|
||||
color: red;
|
||||
display: block;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
}
|
||||
main {
|
||||
padding: 1em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.caption {
|
||||
font-size: 30px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
84
packages/pockethost.io/src/routes/signup/+page.svelte
Normal file
84
packages/pockethost.io/src/routes/signup/+page.svelte
Normal file
@ -0,0 +1,84 @@
|
||||
<script lang="ts">
|
||||
import { authViaEmail, createUser } from '@pockethost/common/src/pocketbase';
|
||||
import Button from '../../components/Button/Button.svelte';
|
||||
import { parseError } from '../../components/Error/parseError';
|
||||
import Title from '../../components/Title.svelte';
|
||||
|
||||
let email = '';
|
||||
let errorMessage = '';
|
||||
let password = '';
|
||||
let passwordError = '';
|
||||
|
||||
// client.users
|
||||
// .authViaEmail('ben@benallfree.com', 'Dhjb2X6C1y0W')
|
||||
// .then((u) => {
|
||||
// console.log(`user logged in`, u)
|
||||
// window.location.href = '/dashboard'
|
||||
// })
|
||||
// .catch((e) => console.error(`user login error`, e))
|
||||
|
||||
const handleSignup = () => {
|
||||
errorMessage = '';
|
||||
passwordError = '';
|
||||
createUser(email, password)
|
||||
.then((user) => {
|
||||
console.log({ user });
|
||||
|
||||
authViaEmail(email, password)
|
||||
.then((u) => {
|
||||
console.log(`user logged in`, u);
|
||||
window.location.href = '/dashboard';
|
||||
})
|
||||
.catch((e) => console.error(`user login error`, e));
|
||||
})
|
||||
.catch((e) => {
|
||||
errorMessage = parseError(e);
|
||||
console.error(errorMessage, e);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<Title first="Sign" second="Up" />
|
||||
|
||||
<main>
|
||||
<div>
|
||||
<label for="email">Email</label>
|
||||
<input name="email" type="email" bind:value={email} />
|
||||
<error>{errorMessage}</error>
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password</label>
|
||||
<input name="password" type="password" bind:value={password} />
|
||||
<error>{passwordError}</error>
|
||||
</div>
|
||||
<Button click={handleSignup} disabled={email.length === 0 || password.length === 0}>
|
||||
Sign Up
|
||||
</Button>
|
||||
<div>
|
||||
Already have an account? <a href="/login">Log in</a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style type="text/scss">
|
||||
error {
|
||||
color: red;
|
||||
display: block;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
}
|
||||
main {
|
||||
padding: 1em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.caption {
|
||||
font-size: 30px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
4
packages/pockethost.io/src/types.ts
Normal file
4
packages/pockethost.io/src/types.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export type MessageField = {
|
||||
code: string
|
||||
message: string
|
||||
}
|
4
packages/pockethost.io/src/util/redirect.ts
Normal file
4
packages/pockethost.io/src/util/redirect.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const redirect = (url: string) => {
|
||||
if (typeof window === 'undefined') return
|
||||
window.location.href = url
|
||||
}
|
BIN
packages/pockethost.io/static/favicon.png
Normal file
BIN
packages/pockethost.io/static/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
63
packages/pockethost.io/static/global.css
Normal file
63
packages/pockethost.io/static/global.css
Normal file
@ -0,0 +1,63 @@
|
||||
html, body {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgb(0,100,200);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: rgb(0,80,160);
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
input, button, select, textarea {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
-webkit-padding: 0.4em 0;
|
||||
padding: 0.4em;
|
||||
margin: 0 0 0.5em 0;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
input:disabled {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
button {
|
||||
color: #333;
|
||||
background-color: #f4f4f4;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
button:not(:disabled):active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
border-color: #666;
|
||||
}
|
14
packages/pockethost.io/svelte.config.js
Normal file
14
packages/pockethost.io/svelte.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
import adapter from '@sveltejs/adapter-node'
|
||||
import preprocess from 'svelte-preprocess'
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://github.com/sveltejs/svelte-preprocess
|
||||
// for more information about preprocessors
|
||||
preprocess: preprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter({ out: 'dist-server' }) },
|
||||
}
|
||||
|
||||
export default config
|
18
packages/pockethost.io/tsconfig.json
Normal file
18
packages/pockethost.io/tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
11
packages/pockethost.io/vite.config.ts
Normal file
11
packages/pockethost.io/vite.config.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite'
|
||||
import type { UserConfig } from 'vite'
|
||||
|
||||
const config: UserConfig = {
|
||||
plugins: [sveltekit()],
|
||||
optimizeDeps: {
|
||||
include: ['highlight.js', 'highlight.js/lib/core'],
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
2886
packages/pockethost.io/yarn-error.log
Normal file
2886
packages/pockethost.io/yarn-error.log
Normal file
File diff suppressed because it is too large
Load Diff
1352
packages/pockethost.io/yarn.lock
Normal file
1352
packages/pockethost.io/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user