mirror of
https://github.com/pockethost/pockethost.git
synced 2025-07-03 11:22:29 +00:00
v0.8 support
This commit is contained in:
parent
1661bf6821
commit
870870e62b
@ -1,4 +1,4 @@
|
|||||||
FROM node:18-alpine as buildbox
|
FROM node:18-alpine as pockethost-buildbox
|
||||||
COPY --from=golang:1.19-alpine /usr/local/go/ /usr/local/go/
|
COPY --from=golang:1.19-alpine /usr/local/go/ /usr/local/go/
|
||||||
ENV PATH="/usr/local/go/bin:${PATH}"
|
ENV PATH="/usr/local/go/bin:${PATH}"
|
||||||
RUN apk add python3 py3-pip make gcc musl-dev g++ bash
|
RUN apk add python3 py3-pip make gcc musl-dev g++ bash
|
||||||
|
8
Dockerfile-prod
Normal file
8
Dockerfile-prod
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FROM node:18-alpine as pockethost-buildbox
|
||||||
|
COPY --from=golang:1.19-alpine /usr/local/go/ /usr/local/go/
|
||||||
|
ENV PATH="/usr/local/go/bin:${PATH}"
|
||||||
|
RUN apk add python3 py3-pip make gcc musl-dev g++ bash
|
||||||
|
WORKDIR /src
|
||||||
|
COPY . .
|
||||||
|
RUN yarn
|
||||||
|
RUN yarn build
|
16
docker/build.yaml
Normal file
16
docker/build.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
build:
|
||||||
|
env_file:
|
||||||
|
- .env.local
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: build
|
||||||
|
working_dir: /src
|
||||||
|
command: bash -c "yarn && yarn build"
|
||||||
|
volumes:
|
||||||
|
- ./mount/cache/go:/go
|
||||||
|
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
||||||
|
- ..:/src
|
@ -1,39 +1,6 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
prepbox:
|
|
||||||
env_file:
|
|
||||||
- .env.local
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: prepbox
|
|
||||||
working_dir: /src
|
|
||||||
command: bash -c "yarn"
|
|
||||||
volumes:
|
|
||||||
- ./mount/cache/go:/go
|
|
||||||
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
|
||||||
- ..:/src
|
|
||||||
profiles: ['build']
|
|
||||||
buildbox:
|
|
||||||
environment:
|
|
||||||
- GOPATH=/go
|
|
||||||
env_file:
|
|
||||||
- .env.local
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: buildbox
|
|
||||||
working_dir: /src
|
|
||||||
command: bash -c "yarn build"
|
|
||||||
volumes:
|
|
||||||
- ./mount/cache/go:/go
|
|
||||||
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
|
||||||
- ..:/src
|
|
||||||
depends_on:
|
|
||||||
prepbox:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
profiles: ['build']
|
|
||||||
www:
|
www:
|
||||||
env_file:
|
env_file:
|
||||||
- .env.local
|
- .env.local
|
||||||
@ -45,7 +12,6 @@ services:
|
|||||||
working_dir: /src
|
working_dir: /src
|
||||||
command: bash -c "yarn dev:www --host=www"
|
command: bash -c "yarn dev:www --host=www"
|
||||||
volumes:
|
volumes:
|
||||||
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
|
||||||
- ..:/src
|
- ..:/src
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
@ -54,7 +20,6 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
daemon:
|
daemon:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
profiles: ['serve']
|
|
||||||
daemon:
|
daemon:
|
||||||
env_file:
|
env_file:
|
||||||
- .env.local
|
- .env.local
|
||||||
@ -67,14 +32,11 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./mount/daemon/instances:/data
|
- ./mount/daemon/instances:/data
|
||||||
- ./mount/cache/go:/go
|
|
||||||
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
|
||||||
- ..:/src
|
- ..:/src
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
ports:
|
ports:
|
||||||
- '9001:3000'
|
- '9001:3000'
|
||||||
profiles: ['serve']
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:mainline-alpine
|
image: nginx:mainline-alpine
|
||||||
container_name: nginx
|
container_name: nginx
|
||||||
@ -91,7 +53,6 @@ services:
|
|||||||
- ./mount/nginx/ssl:/mount/nginx/ssl
|
- ./mount/nginx/ssl:/mount/nginx/ssl
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
profiles: ['serve']
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
app-network:
|
app-network:
|
16
docker/install.yaml
Normal file
16
docker/install.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
prepbox:
|
||||||
|
env_file:
|
||||||
|
- .env.local
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: prepbox
|
||||||
|
working_dir: /src
|
||||||
|
command: bash -c "yarn"
|
||||||
|
volumes:
|
||||||
|
- ./mount/cache/go:/go
|
||||||
|
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
||||||
|
- ..:/src
|
17
docker/migrate-dev.yaml
Normal file
17
docker/migrate-dev.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
prepbox:
|
||||||
|
env_file:
|
||||||
|
- .env.local
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: prepbox
|
||||||
|
working_dir: /src
|
||||||
|
command: bash -c "yarn migrate"
|
||||||
|
volumes:
|
||||||
|
- ./mount/daemon/instances:/data
|
||||||
|
- ./mount/cache/go:/go
|
||||||
|
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
||||||
|
- ..:/src
|
17
docker/migrate-prod.yaml
Normal file
17
docker/migrate-prod.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
prepbox:
|
||||||
|
env_file:
|
||||||
|
- .env.local
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: prepbox
|
||||||
|
working_dir: /src
|
||||||
|
command: bash -c "yarn && yarn build && yarn migrate"
|
||||||
|
volumes:
|
||||||
|
- /home/pockethost/data:/data
|
||||||
|
- ./mount/cache/go:/go
|
||||||
|
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
||||||
|
- ..:/src
|
@ -1,41 +1,6 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
prepbox:
|
|
||||||
environment:
|
|
||||||
- GOPATH=/go
|
|
||||||
env_file:
|
|
||||||
- .env.local
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: prepbox
|
|
||||||
working_dir: /src
|
|
||||||
command: bash -c "yarn"
|
|
||||||
volumes:
|
|
||||||
- ./mount/cache/go:/go
|
|
||||||
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
|
||||||
- ..:/src
|
|
||||||
profiles: ['build']
|
|
||||||
buildbox:
|
|
||||||
environment:
|
|
||||||
- GOPATH=/go
|
|
||||||
env_file:
|
|
||||||
- .env.local
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: buildbox
|
|
||||||
working_dir: /src
|
|
||||||
command: bash -c "yarn build"
|
|
||||||
volumes:
|
|
||||||
- ./mount/cache/go:/go
|
|
||||||
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
|
||||||
- ..:/src
|
|
||||||
depends_on:
|
|
||||||
prepbox:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
profiles: ['build']
|
|
||||||
www:
|
www:
|
||||||
env_file:
|
env_file:
|
||||||
- .env.local
|
- .env.local
|
||||||
@ -47,7 +12,6 @@ services:
|
|||||||
working_dir: /src
|
working_dir: /src
|
||||||
command: bash -c "yarn start:www --host=www"
|
command: bash -c "yarn start:www --host=www"
|
||||||
volumes:
|
volumes:
|
||||||
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
|
||||||
- ..:/src
|
- ..:/src
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
@ -56,7 +20,6 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
daemon:
|
daemon:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
profiles: ['serve']
|
|
||||||
daemon:
|
daemon:
|
||||||
env_file:
|
env_file:
|
||||||
- .env.local
|
- .env.local
|
||||||
@ -71,14 +34,11 @@ services:
|
|||||||
- SHELL=/bin/bash
|
- SHELL=/bin/bash
|
||||||
volumes:
|
volumes:
|
||||||
- /home/pockethost/data:/data
|
- /home/pockethost/data:/data
|
||||||
- ./mount/cache/go:/go
|
|
||||||
- ./mount/cache/yarn:/usr/local/share/.cache/yarn/v6
|
|
||||||
- ..:/src
|
- ..:/src
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
ports:
|
ports:
|
||||||
- '9001:3000'
|
- '9001:3000'
|
||||||
profiles: ['serve']
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:mainline-alpine
|
image: nginx:mainline-alpine
|
||||||
container_name: nginx
|
container_name: nginx
|
||||||
@ -95,7 +55,6 @@ services:
|
|||||||
- ./mount/nginx/ssl:/mount/nginx/ssl
|
- ./mount/nginx/ssl:/mount/nginx/ssl
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
profiles: ['serve']
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
app-network:
|
app-network:
|
@ -15,7 +15,9 @@
|
|||||||
"dev:daemon": "cd packages/daemon && yarn dev",
|
"dev:daemon": "cd packages/daemon && yarn dev",
|
||||||
"start": "concurrently 'yarn start:www' 'yarn start:daemon'",
|
"start": "concurrently 'yarn start:www' 'yarn start:daemon'",
|
||||||
"start:www": "cd packages/pockethost.io && yarn start",
|
"start:www": "cd packages/pockethost.io && yarn start",
|
||||||
"start:daemon": "cd packages/daemon && yarn start"
|
"start:daemon": "cd packages/daemon && yarn start",
|
||||||
|
"migrate": "yarn migrate:daemon",
|
||||||
|
"migrate:daemon": "cd packages/daemon && yarn migrate"
|
||||||
},
|
},
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"packages": [
|
"packages": [
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
"cross-fetch": "^3.1.5",
|
"cross-fetch": "^3.1.5",
|
||||||
"eventsource": "^2.0.2",
|
"eventsource": "^2.0.2",
|
||||||
"find-up": "^6.3.0",
|
"find-up": "^6.3.0",
|
||||||
"pocketbase": "^0.7.1",
|
"pocketbase": "^0.8.0-rc1",
|
||||||
"prompts": "^2.4.2",
|
"prompts": "^2.4.2",
|
||||||
"tmp": "^0.2.1"
|
"tmp": "^0.2.1"
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,6 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@s-libs/micro-dash": "^14.1.0",
|
"@s-libs/micro-dash": "^14.1.0",
|
||||||
"nanoid": "^4.0.0",
|
"nanoid": "^4.0.0",
|
||||||
"pocketbase": "^0.7.0"
|
"pocketbase": "^0.8.0-rc1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,38 @@
|
|||||||
import PocketBase from 'pocketbase'
|
import PocketBase, { Record } from 'pocketbase'
|
||||||
|
import { CollectionName, RecordId } from './schema'
|
||||||
|
|
||||||
|
export interface RecordSubscription<T = Record> {
|
||||||
|
action: string
|
||||||
|
record: T
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RealtimeEventHandler<TRec> = (e: RecordSubscription<TRec>) => void
|
||||||
|
|
||||||
export const createRealtimeSubscriptionManager = (pocketbase: PocketBase) => {
|
export const createRealtimeSubscriptionManager = (pocketbase: PocketBase) => {
|
||||||
const subscriptions: { [_: string]: number } = {}
|
const subscriptions: { [_: string]: number } = {}
|
||||||
|
|
||||||
const subscribe = <TRec>(slug: string, cb: (rec: TRec) => void) => {
|
const subscribeOne = <TRec>(
|
||||||
|
collection: CollectionName,
|
||||||
|
id: RecordId,
|
||||||
|
cb: (e: RecordSubscription<TRec>) => void
|
||||||
|
) => {
|
||||||
|
const slug = `${collection}/${id}`
|
||||||
if (subscriptions[slug]) {
|
if (subscriptions[slug]) {
|
||||||
subscriptions[slug]++
|
subscriptions[slug]++
|
||||||
} else {
|
} else {
|
||||||
subscriptions[slug] = 1
|
subscriptions[slug] = 1
|
||||||
pocketbase.realtime.subscribe(slug, (e) => {
|
pocketbase.collection(collection).subscribeOne<TRec>(id, (e) => {
|
||||||
console.log(`Realtime update`, { e })
|
console.log(`Realtime update`, { e })
|
||||||
cb(e.record as unknown as TRec)
|
cb(e)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
subscriptions[slug]--
|
subscriptions[slug]--
|
||||||
if (subscriptions[slug] === 0) {
|
if (subscriptions[slug] === 0) {
|
||||||
pocketbase.realtime.unsubscribe(slug)
|
pocketbase.collection(collection).unsubscribe(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return subscribe
|
return { subscribeOne }
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export function assertExists<TType>(
|
export function assertExists<TType>(
|
||||||
v: unknown,
|
v: TType,
|
||||||
message = `Value does not exist`
|
message = `Value does not exist`
|
||||||
): asserts v is NonNullable<TType> {
|
): asserts v is NonNullable<TType> {
|
||||||
if (typeof v === 'undefined') {
|
if (typeof v === 'undefined') {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export * from './assert'
|
export * from './assert'
|
||||||
export * from './RealtimeSubscriptionManager'
|
export * from './RealtimeSubscriptionManager'
|
||||||
|
export * from './releases'
|
||||||
export * from './schema'
|
export * from './schema'
|
||||||
|
142
packages/common/src/release-names.txt
Normal file
142
packages/common/src/release-names.txt
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
Abbey
|
||||||
|
Ace
|
||||||
|
Alice
|
||||||
|
Alvin
|
||||||
|
Amber
|
||||||
|
Andy
|
||||||
|
Bailey
|
||||||
|
Bart
|
||||||
|
Becca
|
||||||
|
Belle
|
||||||
|
Benny
|
||||||
|
Biscuit
|
||||||
|
Bonnie
|
||||||
|
Boo
|
||||||
|
Brooke
|
||||||
|
Bruno
|
||||||
|
Bunny
|
||||||
|
Buttons
|
||||||
|
Callie
|
||||||
|
Carmen
|
||||||
|
Cassidy
|
||||||
|
Charlotte
|
||||||
|
Chase
|
||||||
|
Cheeks
|
||||||
|
China
|
||||||
|
Cindy
|
||||||
|
Cinnamon
|
||||||
|
Cody
|
||||||
|
Cookie
|
||||||
|
Crumpet
|
||||||
|
Cupcake
|
||||||
|
Daisy
|
||||||
|
Dallas
|
||||||
|
Dancer
|
||||||
|
Dani
|
||||||
|
Dasher
|
||||||
|
Deckle
|
||||||
|
Dirk
|
||||||
|
Doily
|
||||||
|
Dresden
|
||||||
|
Droplet
|
||||||
|
Elliott
|
||||||
|
Emily
|
||||||
|
Emma
|
||||||
|
Fancy
|
||||||
|
Fifi
|
||||||
|
Fiona
|
||||||
|
Flake
|
||||||
|
Fluffy
|
||||||
|
Frankie
|
||||||
|
Frisky
|
||||||
|
Frosty
|
||||||
|
Frosty
|
||||||
|
Giggles
|
||||||
|
Ginger
|
||||||
|
Goofball
|
||||||
|
Gordon
|
||||||
|
Gretel
|
||||||
|
Gumdrop
|
||||||
|
Gus
|
||||||
|
Haley
|
||||||
|
Hansel
|
||||||
|
Harry
|
||||||
|
Honeybunches
|
||||||
|
Hugsgy
|
||||||
|
Humphrey
|
||||||
|
Hunny
|
||||||
|
Ike
|
||||||
|
Iris
|
||||||
|
Jackie
|
||||||
|
Jangles
|
||||||
|
Jellybean
|
||||||
|
Jenna
|
||||||
|
Jesse
|
||||||
|
Joey
|
||||||
|
Josie
|
||||||
|
Junior
|
||||||
|
Kelly
|
||||||
|
Kibbles
|
||||||
|
Killer
|
||||||
|
Kim
|
||||||
|
Kit Kat
|
||||||
|
Ladybug
|
||||||
|
Laurie
|
||||||
|
Leo
|
||||||
|
Li’l Nibbler
|
||||||
|
Maddie
|
||||||
|
Maple Syrup
|
||||||
|
Marshmallow
|
||||||
|
Maximilian
|
||||||
|
Maxine
|
||||||
|
Mickey
|
||||||
|
Mimi
|
||||||
|
Mr. Gopher
|
||||||
|
Muffin
|
||||||
|
Nibbler
|
||||||
|
Nibbly
|
||||||
|
Nora
|
||||||
|
Opal
|
||||||
|
Oscar
|
||||||
|
Pansy
|
||||||
|
Peach
|
||||||
|
Philbert
|
||||||
|
Pierre
|
||||||
|
Pixie
|
||||||
|
Poofball
|
||||||
|
Powderpuff
|
||||||
|
Precious
|
||||||
|
Puddin’
|
||||||
|
Quinn
|
||||||
|
Rainbow Dash
|
||||||
|
Ralph
|
||||||
|
Ripple
|
||||||
|
Rockin’ Robin
|
||||||
|
Rocky
|
||||||
|
Rosie
|
||||||
|
Rudolph
|
||||||
|
Runt
|
||||||
|
Rusty
|
||||||
|
Sadie
|
||||||
|
Sandy
|
||||||
|
Sawyer
|
||||||
|
Scout
|
||||||
|
Simon
|
||||||
|
Snowball
|
||||||
|
Snuggles
|
||||||
|
Sophie
|
||||||
|
Spike
|
||||||
|
Stella
|
||||||
|
Sugarplum
|
||||||
|
Sunny
|
||||||
|
Sweetie Pie
|
||||||
|
Sydney
|
||||||
|
Tadpole
|
||||||
|
Tammy
|
||||||
|
Tater Tot
|
||||||
|
Tori
|
||||||
|
Twinkle
|
||||||
|
Wally
|
||||||
|
Whiskers
|
||||||
|
Willow
|
||||||
|
Zelda
|
57
packages/common/src/releases.ts
Normal file
57
packages/common/src/releases.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { find, last } from '@s-libs/micro-dash'
|
||||||
|
import { assertExists } from './assert'
|
||||||
|
|
||||||
|
export const RELEASES = {
|
||||||
|
ermine: {
|
||||||
|
weight: 1,
|
||||||
|
versions: ['0.7.9', '0.7.8', '0.7.7'],
|
||||||
|
},
|
||||||
|
lollipop: {
|
||||||
|
weight: 2,
|
||||||
|
versions: ['0.8.0-rc1'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PlatformId = keyof typeof RELEASES
|
||||||
|
export type VersionId = string
|
||||||
|
|
||||||
|
export const LATEST_PLATFORM: keyof typeof RELEASES = 'lollipop'
|
||||||
|
|
||||||
|
export const USE_LATEST_VERSION = 'latest'
|
||||||
|
|
||||||
|
function assertPlatform(platformId: string): asserts platformId is PlatformId {
|
||||||
|
const hasPlatform = platformId in RELEASES
|
||||||
|
if (!hasPlatform) {
|
||||||
|
throw new Error(`Expected ${platformId} to exist here`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { assertPlatform }
|
||||||
|
|
||||||
|
export const versionFor = (platformId: PlatformId, version: VersionId) => {
|
||||||
|
const platform = RELEASES[platformId]
|
||||||
|
if (version === USE_LATEST_VERSION) {
|
||||||
|
const _v = last(platform.versions)
|
||||||
|
assertExists(_v, `Expected ${platformId} to have versions (latest)`)
|
||||||
|
return _v
|
||||||
|
}
|
||||||
|
const _v = find(platform.versions, (v) => v === version)
|
||||||
|
assertExists(_v, `Expected ${platformId} to have version (${version})`)
|
||||||
|
return _v
|
||||||
|
}
|
||||||
|
|
||||||
|
export const binFor = (
|
||||||
|
platformId: PlatformId,
|
||||||
|
version: VersionId = 'latest'
|
||||||
|
) => {
|
||||||
|
const _version = versionFor(platformId, version)
|
||||||
|
return `pocketbase-${platformId}-${_version}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const humanVersion = (platformId: PlatformId, version: VersionId) => {
|
||||||
|
const platform = RELEASES[platformId]
|
||||||
|
const _version = versionFor(platformId, version)
|
||||||
|
const humanVersion =
|
||||||
|
version === USE_LATEST_VERSION ? `${_version} (latest)` : _version
|
||||||
|
return humanVersion
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
import { PlatformId, VersionId } from './releases'
|
||||||
|
|
||||||
export type RecordId = string
|
export type RecordId = string
|
||||||
export type UserId = RecordId
|
export type UserId = RecordId
|
||||||
export type InstanceId = RecordId
|
export type InstanceId = RecordId
|
||||||
@ -8,6 +10,7 @@ export type IsoDate = string
|
|||||||
export type ProcessId = number
|
export type ProcessId = number
|
||||||
export type Username = string
|
export type Username = string
|
||||||
export type Password = string
|
export type Password = string
|
||||||
|
export type CollectionName = string
|
||||||
|
|
||||||
export const pocketNow = () => new Date().toISOString()
|
export const pocketNow = () => new Date().toISOString()
|
||||||
|
|
||||||
@ -20,26 +23,21 @@ export enum InstanceStatus {
|
|||||||
Failed = 'failed',
|
Failed = 'failed',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Instance_In = {
|
export type InstancesRecord = {
|
||||||
uid?: UserId
|
id: RecordId
|
||||||
subdomain?: Subdomain
|
|
||||||
status?: InstanceStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PocketbaseRecord<TIdType extends RecordId> = {
|
|
||||||
id: TIdType
|
|
||||||
created: IsoDate
|
|
||||||
updated: IsoDate
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Instance_Out = PocketbaseRecord<InstanceId> & {
|
|
||||||
uid: UserId
|
|
||||||
subdomain: Subdomain
|
subdomain: Subdomain
|
||||||
|
uid: UserId
|
||||||
status: InstanceStatus
|
status: InstanceStatus
|
||||||
|
platform: PlatformId
|
||||||
|
version: VersionId
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Any_Record_Out = Instance_Out
|
export type InstancesRecord_New = Omit<InstancesRecord, 'id'>
|
||||||
|
|
||||||
export type Instance_Out_ByIdCollection = {
|
export type UserRecord = {
|
||||||
[_: InstanceId]: Instance_Out
|
id: RecordId
|
||||||
|
email: string
|
||||||
|
verified: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type InstanceRecordById = { [_: InstanceId]: InstancesRecord }
|
||||||
|
@ -3,45 +3,24 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "mkdir -p dist && esbuild src/server.ts --bundle --platform=node > dist/server.js && echo 'Build complete' `date`",
|
"build": "echo 'Build complete' `date`",
|
||||||
"dev": "yarn build && concurrently 'yarn dev:watch' 'yarn dev:serve'",
|
"dev": "tsx watch src/server.ts",
|
||||||
"dev:watch": "chokidar 'src/**' '../pocketbase/src/**' -c 'yarn build'",
|
"start": "tsx src/server.ts",
|
||||||
"dev:serve": "nodemon dist/server.js",
|
"migrate": "tsx src/migrate/migrate.ts"
|
||||||
"start": "node dist/server.js"
|
|
||||||
},
|
|
||||||
"targets": {
|
|
||||||
"server": {
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"source": "src/server.ts",
|
|
||||||
"includeNodeModules": [
|
|
||||||
"@pockethost/common",
|
|
||||||
"get-port",
|
|
||||||
"pocketbase",
|
|
||||||
"@s-libs/micro-dash"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pockethost/common": "0.0.1",
|
"@pockethost/common": "0.0.1",
|
||||||
"@s-libs/micro-dash": "^14.1.0",
|
"@s-libs/micro-dash": "^14.1.0",
|
||||||
"@types/http-proxy": "^1.17.9",
|
"@types/http-proxy": "^1.17.9",
|
||||||
|
"@types/node": "^18.11.9",
|
||||||
"bottleneck": "^2.19.5",
|
"bottleneck": "^2.19.5",
|
||||||
"chokidar-cli": "^3.0.0",
|
|
||||||
"event-source-polyfill": "^1.0.31",
|
"event-source-polyfill": "^1.0.31",
|
||||||
"get-port": "^6.1.2",
|
"get-port": "^6.1.2",
|
||||||
"http-proxy": "^1.18.1",
|
"http-proxy": "^1.18.1",
|
||||||
"node-fetch": "^3.2.10",
|
"node-fetch": "^3.2.10",
|
||||||
"pocketbase": "^0.7.0",
|
"pocketbase": "^0.8.0-rc1"
|
||||||
"ts-node": "^10.9.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chokidar-cli": "^3.0.0",
|
"tsx": "^3.11.0"
|
||||||
"concurrently": "^7.4.0",
|
|
||||||
"esbuild": "^0.15.11",
|
|
||||||
"nodemon": "^2.0.20",
|
|
||||||
"parcel": "^2.7.0",
|
|
||||||
"ts-node": "^10.9.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,12 +1,9 @@
|
|||||||
import { InstanceStatus } from '@pockethost/common'
|
import { binFor, InstanceStatus } from '@pockethost/common'
|
||||||
import { forEachRight, map } from '@s-libs/micro-dash'
|
import { forEachRight, map } from '@s-libs/micro-dash'
|
||||||
import Bottleneck from 'bottleneck'
|
import Bottleneck from 'bottleneck'
|
||||||
import { ChildProcessWithoutNullStreams, spawn } from 'child_process'
|
import { ChildProcessWithoutNullStreams } from 'child_process'
|
||||||
import getPort from 'get-port'
|
import getPort from 'get-port'
|
||||||
import fetch from 'node-fetch'
|
|
||||||
import {
|
import {
|
||||||
DAEMON_PB_BIN_DIR,
|
|
||||||
DAEMON_PB_DATA_DIR,
|
|
||||||
DAEMON_PB_IDLE_TTL,
|
DAEMON_PB_IDLE_TTL,
|
||||||
DAEMON_PB_PASSWORD,
|
DAEMON_PB_PASSWORD,
|
||||||
DAEMON_PB_PORT_BASE,
|
DAEMON_PB_PORT_BASE,
|
||||||
@ -17,8 +14,10 @@ import {
|
|||||||
PUBLIC_PB_PROTOCOL,
|
PUBLIC_PB_PROTOCOL,
|
||||||
PUBLIC_PB_SUBDOMAIN,
|
PUBLIC_PB_SUBDOMAIN,
|
||||||
} from './constants'
|
} from './constants'
|
||||||
import { collections_001 } from './migrations'
|
|
||||||
import { createPbClient } from './PbClient'
|
import { createPbClient } from './PbClient'
|
||||||
|
import { mkInternalUrl } from './util/internal'
|
||||||
|
import { tryFetch } from './util/tryFetch'
|
||||||
|
import { _spawn } from './util/_spawn'
|
||||||
|
|
||||||
type Instance = {
|
type Instance = {
|
||||||
process: ChildProcessWithoutNullStreams
|
process: ChildProcessWithoutNullStreams
|
||||||
@ -29,80 +28,15 @@ type Instance = {
|
|||||||
startRequest: () => () => void
|
startRequest: () => () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
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 to ${url} successful`)
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(`Could not connect to ${url}`)
|
|
||||||
setTimeout(tryFetch, 1000)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
tryFetch()
|
|
||||||
})
|
|
||||||
|
|
||||||
const mkInternalAddress = (port: number) => `127.0.0.1:${port}`
|
|
||||||
const mkInternalUrl = (port: number) => `http://${mkInternalAddress(port)}`
|
|
||||||
|
|
||||||
export const createInstanceManger = async () => {
|
export const createInstanceManger = async () => {
|
||||||
const instances: { [_: string]: Instance } = {}
|
const instances: { [_: string]: Instance } = {}
|
||||||
|
|
||||||
const _spawn = async (cfg: {
|
|
||||||
subdomain: string
|
|
||||||
port: number
|
|
||||||
bin: string
|
|
||||||
}) => {
|
|
||||||
const { subdomain, port, bin } = cfg
|
|
||||||
const cmd = `${DAEMON_PB_BIN_DIR}/${bin}`
|
|
||||||
|
|
||||||
const args = [
|
|
||||||
`serve`,
|
|
||||||
`--dir`,
|
|
||||||
`${DAEMON_PB_DATA_DIR}/${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]
|
|
||||||
if (subdomain !== PUBLIC_PB_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(DAEMON_PB_PORT_BASE)
|
const coreInternalUrl = mkInternalUrl(DAEMON_PB_PORT_BASE)
|
||||||
const client = createPbClient(coreInternalUrl)
|
const client = createPbClient(coreInternalUrl)
|
||||||
const mainProcess = await _spawn({
|
const mainProcess = await _spawn({
|
||||||
subdomain: PUBLIC_PB_SUBDOMAIN,
|
subdomain: PUBLIC_PB_SUBDOMAIN,
|
||||||
port: DAEMON_PB_PORT_BASE,
|
port: DAEMON_PB_PORT_BASE,
|
||||||
bin: 'pocketbase',
|
bin: binFor('lollipop'),
|
||||||
})
|
})
|
||||||
instances[PUBLIC_PB_SUBDOMAIN] = {
|
instances[PUBLIC_PB_SUBDOMAIN] = {
|
||||||
process: mainProcess,
|
process: mainProcess,
|
||||||
@ -118,7 +52,6 @@ export const createInstanceManger = async () => {
|
|||||||
await tryFetch(coreInternalUrl)
|
await tryFetch(coreInternalUrl)
|
||||||
try {
|
try {
|
||||||
await client.adminAuthViaEmail(DAEMON_PB_USERNAME, DAEMON_PB_PASSWORD)
|
await client.adminAuthViaEmail(DAEMON_PB_USERNAME, DAEMON_PB_PASSWORD)
|
||||||
await client.migrate(collections_001)
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(
|
console.error(
|
||||||
`***WARNING*** CANNOT AUTHENTICATE TO ${PUBLIC_PB_PROTOCOL}://${PUBLIC_PB_SUBDOMAIN}.${PUBLIC_PB_DOMAIN}/_/`
|
`***WARNING*** CANNOT AUTHENTICATE TO ${PUBLIC_PB_PROTOCOL}://${PUBLIC_PB_SUBDOMAIN}.${PUBLIC_PB_DOMAIN}/_/`
|
||||||
@ -160,7 +93,7 @@ export const createInstanceManger = async () => {
|
|||||||
console.log(`${subdomain} found in DB`)
|
console.log(`${subdomain} found in DB`)
|
||||||
const exclude = map(instances, (i) => i.port)
|
const exclude = map(instances, (i) => i.port)
|
||||||
const newPort = await getPort({
|
const newPort = await getPort({
|
||||||
port: 8090,
|
port: DAEMON_PB_PORT_BASE,
|
||||||
exclude,
|
exclude,
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.error(`Failed to get port for ${subdomain}`)
|
console.error(`Failed to get port for ${subdomain}`)
|
||||||
@ -173,7 +106,15 @@ export const createInstanceManger = async () => {
|
|||||||
const childProcess = await _spawn({
|
const childProcess = await _spawn({
|
||||||
subdomain,
|
subdomain,
|
||||||
port: newPort,
|
port: newPort,
|
||||||
bin: instance.bin || 'pocketbase',
|
bin: binFor(instance.platform, instance.version),
|
||||||
|
cleanup: (code) => {
|
||||||
|
instances[subdomain]?.heartbeat(true)
|
||||||
|
delete instances[subdomain]
|
||||||
|
if (subdomain !== PUBLIC_PB_SUBDOMAIN) {
|
||||||
|
client.updateInstanceStatus(subdomain, InstanceStatus.Idle)
|
||||||
|
}
|
||||||
|
console.log(`${subdomain} exited with code ${code}`)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const api: Instance = (() => {
|
const api: Instance = (() => {
|
||||||
|
@ -1,19 +1,9 @@
|
|||||||
import { InstanceStatus } from '@pockethost/common'
|
import { InstancesRecord, InstanceStatus, UserRecord } from '@pockethost/common'
|
||||||
import PocketBase, { Record, User } from 'pocketbase'
|
import { reduce } from '@s-libs/micro-dash'
|
||||||
import { Collection_Serialized } from './migrations'
|
import Bottleneck from 'bottleneck'
|
||||||
|
import PocketBase, { Collection } from 'pocketbase'
|
||||||
const safeCatch = <TIn extends any[], TOut>(
|
import { Collection_Serialized } from './migrate/migrations'
|
||||||
name: string,
|
import { safeCatch } from './util/safeCatch'
|
||||||
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) => {
|
export const createPbClient = (url: string) => {
|
||||||
console.log(`Initializing client: ${url}`)
|
console.log(`Initializing client: ${url}`)
|
||||||
@ -22,14 +12,15 @@ export const createPbClient = (url: string) => {
|
|||||||
const adminAuthViaEmail = safeCatch(
|
const adminAuthViaEmail = safeCatch(
|
||||||
`adminAuthViaEmail`,
|
`adminAuthViaEmail`,
|
||||||
(email: string, password: string) =>
|
(email: string, password: string) =>
|
||||||
client.admins.authViaEmail(email, password)
|
client.admins.authWithPassword(email, password)
|
||||||
)
|
)
|
||||||
|
|
||||||
const getInstanceBySubdomain = safeCatch(
|
const getInstanceBySubdomain = safeCatch(
|
||||||
`getInstanceBySubdomain`,
|
`getInstanceBySubdomain`,
|
||||||
(subdomain: string): Promise<[Record, User] | []> =>
|
(subdomain: string): Promise<[InstancesRecord, UserRecord] | []> =>
|
||||||
client.records
|
client
|
||||||
.getList(`instances`, 1, 1, {
|
.collection('instances')
|
||||||
|
.getList<InstancesRecord>(1, 1, {
|
||||||
filter: `subdomain = '${subdomain}'`,
|
filter: `subdomain = '${subdomain}'`,
|
||||||
})
|
})
|
||||||
.then((recs) => {
|
.then((recs) => {
|
||||||
@ -40,9 +31,12 @@ export const createPbClient = (url: string) => {
|
|||||||
}
|
}
|
||||||
const [instance] = recs.items
|
const [instance] = recs.items
|
||||||
if (!instance) return []
|
if (!instance) return []
|
||||||
return client.users.getOne(instance.uid).then((user) => {
|
return client
|
||||||
return [instance, user]
|
.collection('users')
|
||||||
})
|
.getOne<UserRecord>(instance.uid)
|
||||||
|
.then((user) => {
|
||||||
|
return [instance, user]
|
||||||
|
})
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,14 +48,41 @@ export const createPbClient = (url: string) => {
|
|||||||
if (!instance) {
|
if (!instance) {
|
||||||
throw new Error(`Expected item here for ${subdomain}`)
|
throw new Error(`Expected item here for ${subdomain}`)
|
||||||
}
|
}
|
||||||
await client.records.update(`instances`, instance.id, { status })
|
await client.collection('instances').update(instance.id, { status })
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const migrate = safeCatch(
|
const migrate = safeCatch(
|
||||||
`migrate`,
|
`migrate`,
|
||||||
async (collections: Collection_Serialized[]) => {
|
async (collections: Collection_Serialized[]) => {
|
||||||
await client.collections.import(collections)
|
await client.collections.import(collections as Collection[])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const updateInstances = safeCatch(
|
||||||
|
'updateInstances',
|
||||||
|
async (cb: (rec: InstancesRecord) => Partial<InstancesRecord>) => {
|
||||||
|
const res = await client
|
||||||
|
.collection('instances')
|
||||||
|
.getFullList<InstancesRecord>(200)
|
||||||
|
const limiter = new Bottleneck({ maxConcurrent: 1 })
|
||||||
|
const promises = reduce(
|
||||||
|
res,
|
||||||
|
(c, r) => {
|
||||||
|
c.push(
|
||||||
|
limiter.schedule(() => {
|
||||||
|
const toUpdate = cb(r)
|
||||||
|
console.log(
|
||||||
|
`Updating instnace ${r.id} with ${JSON.stringify(toUpdate)}`
|
||||||
|
)
|
||||||
|
return client.collection('instances').update(r.id, toUpdate)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
[] as Promise<void>[]
|
||||||
|
)
|
||||||
|
await Promise.all(promises)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -70,5 +91,6 @@ export const createPbClient = (url: string) => {
|
|||||||
getInstanceBySubdomain,
|
getInstanceBySubdomain,
|
||||||
updateInstanceStatus,
|
updateInstanceStatus,
|
||||||
migrate,
|
migrate,
|
||||||
|
updateInstances,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
65
packages/daemon/src/migrate/migrate.ts
Normal file
65
packages/daemon/src/migrate/migrate.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { binFor, InstanceStatus } from '@pockethost/common'
|
||||||
|
import { chdir } from 'process'
|
||||||
|
import {
|
||||||
|
DAEMON_PB_BIN_DIR,
|
||||||
|
DAEMON_PB_DATA_DIR,
|
||||||
|
DAEMON_PB_PASSWORD,
|
||||||
|
DAEMON_PB_PORT_BASE,
|
||||||
|
DAEMON_PB_USERNAME,
|
||||||
|
PUBLIC_PB_DOMAIN,
|
||||||
|
PUBLIC_PB_PROTOCOL,
|
||||||
|
PUBLIC_PB_SUBDOMAIN,
|
||||||
|
} from '../constants'
|
||||||
|
import { createPbClient } from '../PbClient'
|
||||||
|
import { mkInternalUrl } from '../util/internal'
|
||||||
|
import { tryFetch } from '../util/tryFetch'
|
||||||
|
import { _spawn } from '../util/_spawn'
|
||||||
|
import { collections_001 } from './migrations'
|
||||||
|
import { pexec } from './pexec'
|
||||||
|
|
||||||
|
const PB_BIN = `${DAEMON_PB_BIN_DIR}/${binFor('lollipop')}`
|
||||||
|
const DATA_ROOT = `${DAEMON_PB_DATA_DIR}/${PUBLIC_PB_SUBDOMAIN}`
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
console.log(`Backing up`)
|
||||||
|
chdir(DATA_ROOT)
|
||||||
|
await pexec(`tar -czvf ${+new Date()}.tgz pb_data`)
|
||||||
|
|
||||||
|
console.log(`Upgrading`)
|
||||||
|
await pexec(`${PB_BIN} upgrade --dir=pb_data`)
|
||||||
|
|
||||||
|
// Add `platform` and `bin` required columns (migrate db json)
|
||||||
|
try {
|
||||||
|
const mainProcess = await _spawn({
|
||||||
|
subdomain: PUBLIC_PB_SUBDOMAIN,
|
||||||
|
port: DAEMON_PB_PORT_BASE,
|
||||||
|
bin: binFor('lollipop'),
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
const coreInternalUrl = mkInternalUrl(DAEMON_PB_PORT_BASE)
|
||||||
|
const client = createPbClient(coreInternalUrl)
|
||||||
|
await tryFetch(coreInternalUrl)
|
||||||
|
await client.adminAuthViaEmail(DAEMON_PB_USERNAME, DAEMON_PB_PASSWORD)
|
||||||
|
await client.migrate(collections_001)
|
||||||
|
await client.updateInstances((instance) => {
|
||||||
|
return {
|
||||||
|
status: instance.status || InstanceStatus.Idle,
|
||||||
|
platform: instance.platform || 'ermine',
|
||||||
|
version: instance.version || 'latest',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
`***WARNING*** CANNOT AUTHENTICATE TO ${PUBLIC_PB_PROTOCOL}://${PUBLIC_PB_SUBDOMAIN}.${PUBLIC_PB_DOMAIN}/_/`
|
||||||
|
)
|
||||||
|
console.error(
|
||||||
|
`***WARNING*** LOG IN MANUALLY, ADJUST .env, AND RESTART DOCKER`
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
console.log(`Exiting process`)
|
||||||
|
mainProcess.kill()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`${e}`)
|
||||||
|
}
|
||||||
|
})()
|
@ -6,27 +6,90 @@ export type Collection_Serialized = Omit<Partial<Collection>, 'schema'> & {
|
|||||||
|
|
||||||
export const collections_001: Collection_Serialized[] = [
|
export const collections_001: Collection_Serialized[] = [
|
||||||
{
|
{
|
||||||
id: 'systemprofiles0',
|
id: 'etae8tuiaxl6xfv',
|
||||||
name: 'profiles',
|
name: 'instances',
|
||||||
system: true,
|
type: 'base',
|
||||||
listRule: 'userId = @request.user.id',
|
system: false,
|
||||||
viewRule: 'userId = @request.user.id',
|
|
||||||
createRule: 'userId = @request.user.id',
|
|
||||||
updateRule: 'userId = @request.user.id',
|
|
||||||
deleteRule: null,
|
|
||||||
schema: [
|
schema: [
|
||||||
{
|
{
|
||||||
id: 'pbfielduser',
|
id: 'qdtuuld1',
|
||||||
name: 'userId',
|
name: 'subdomain',
|
||||||
type: 'user',
|
type: 'text',
|
||||||
system: true,
|
system: false,
|
||||||
required: true,
|
required: true,
|
||||||
unique: true,
|
unique: true,
|
||||||
options: {
|
options: {
|
||||||
maxSelect: 1,
|
min: null,
|
||||||
cascadeDelete: true,
|
max: 50,
|
||||||
|
pattern: '^[a-z][\\-a-z]+$',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'rbj14krn',
|
||||||
|
name: 'uid',
|
||||||
|
type: 'relation',
|
||||||
|
system: false,
|
||||||
|
required: true,
|
||||||
|
unique: false,
|
||||||
|
options: {
|
||||||
|
maxSelect: 1,
|
||||||
|
collectionId: 'systemprofiles0',
|
||||||
|
cascadeDelete: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'c2y74d7h',
|
||||||
|
name: 'status',
|
||||||
|
type: 'text',
|
||||||
|
system: false,
|
||||||
|
required: true,
|
||||||
|
unique: false,
|
||||||
|
options: {
|
||||||
|
min: null,
|
||||||
|
max: null,
|
||||||
|
pattern: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'yxby5r6b',
|
||||||
|
name: 'platform',
|
||||||
|
type: 'text',
|
||||||
|
system: false,
|
||||||
|
required: true,
|
||||||
|
unique: false,
|
||||||
|
options: {
|
||||||
|
min: null,
|
||||||
|
max: null,
|
||||||
|
pattern: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4ydffkv3',
|
||||||
|
name: 'version',
|
||||||
|
type: 'text',
|
||||||
|
system: false,
|
||||||
|
required: true,
|
||||||
|
unique: false,
|
||||||
|
options: {
|
||||||
|
min: null,
|
||||||
|
max: null,
|
||||||
|
pattern: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
listRule: 'uid=@request.auth.id',
|
||||||
|
viewRule: 'uid = @request.auth.id',
|
||||||
|
createRule: "uid = @request.auth.id && (status = 'idle' || status = '')",
|
||||||
|
updateRule: null,
|
||||||
|
deleteRule: null,
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'systemprofiles0',
|
||||||
|
name: 'users',
|
||||||
|
type: 'auth',
|
||||||
|
system: false,
|
||||||
|
schema: [
|
||||||
{
|
{
|
||||||
id: 'pbfieldname',
|
id: 'pbfieldname',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
@ -61,68 +124,20 @@ export const collections_001: Collection_Serialized[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
listRule: 'id = @request.auth.id',
|
||||||
{
|
viewRule: 'id = @request.auth.id',
|
||||||
id: 'etae8tuiaxl6xfv',
|
createRule: '',
|
||||||
name: 'instances',
|
updateRule: 'id = @request.auth.id',
|
||||||
system: false,
|
|
||||||
listRule: 'uid=@request.user.id',
|
|
||||||
viewRule: 'uid = @request.user.id',
|
|
||||||
createRule: "uid = @request.user.id && (status = 'idle' || status = '')",
|
|
||||||
updateRule: null,
|
|
||||||
deleteRule: null,
|
deleteRule: null,
|
||||||
schema: [
|
options: {
|
||||||
{
|
allowEmailAuth: true,
|
||||||
id: 'qdtuuld1',
|
allowOAuth2Auth: true,
|
||||||
name: 'subdomain',
|
allowUsernameAuth: false,
|
||||||
type: 'text',
|
exceptEmailDomains: null,
|
||||||
system: false,
|
manageRule: null,
|
||||||
required: true,
|
minPasswordLength: 8,
|
||||||
unique: true,
|
onlyEmailDomains: null,
|
||||||
options: {
|
requireEmail: true,
|
||||||
min: null,
|
},
|
||||||
max: 50,
|
|
||||||
pattern: '^[a-z][\\-a-z]+$',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'rbj14krn',
|
|
||||||
name: 'uid',
|
|
||||||
type: 'user',
|
|
||||||
system: false,
|
|
||||||
required: true,
|
|
||||||
unique: false,
|
|
||||||
options: {
|
|
||||||
maxSelect: 1,
|
|
||||||
cascadeDelete: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'c2y74d7h',
|
|
||||||
name: 'status',
|
|
||||||
type: 'text',
|
|
||||||
system: false,
|
|
||||||
required: false,
|
|
||||||
unique: false,
|
|
||||||
options: {
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
pattern: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3rinhcnt',
|
|
||||||
name: 'bin',
|
|
||||||
type: 'text',
|
|
||||||
system: false,
|
|
||||||
required: false,
|
|
||||||
unique: false,
|
|
||||||
options: {
|
|
||||||
min: 0,
|
|
||||||
max: 30,
|
|
||||||
pattern: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
]
|
]
|
16
packages/daemon/src/migrate/pexec.ts
Normal file
16
packages/daemon/src/migrate/pexec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { exec } from 'child_process'
|
||||||
|
|
||||||
|
export const pexec = (cmd: string) => {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
console.log(cmd)
|
||||||
|
exec(cmd, (err, stdout, stderr) => {
|
||||||
|
console.log(stdout)
|
||||||
|
console.error(stderr)
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
55
packages/daemon/src/util/_spawn.ts
Normal file
55
packages/daemon/src/util/_spawn.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { spawn } from 'child_process'
|
||||||
|
import { existsSync } from 'fs'
|
||||||
|
import { DAEMON_PB_BIN_DIR, DAEMON_PB_DATA_DIR } from '../constants'
|
||||||
|
import { mkInternalAddress, mkInternalUrl } from './internal'
|
||||||
|
import { tryFetch } from './tryFetch'
|
||||||
|
|
||||||
|
export const _spawn = async (cfg: {
|
||||||
|
subdomain: string
|
||||||
|
port: number
|
||||||
|
bin: string
|
||||||
|
cleanup?: (code: number | null) => void
|
||||||
|
}) => {
|
||||||
|
const { subdomain, port, bin, cleanup } = cfg
|
||||||
|
const cmd = `${DAEMON_PB_BIN_DIR}/${bin}`
|
||||||
|
if (!existsSync(cmd)) {
|
||||||
|
throw new Error(
|
||||||
|
`PocketBase binary (${bin}) not found. Contact pockethost.io.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const args = [
|
||||||
|
`serve`,
|
||||||
|
`--dir`,
|
||||||
|
`${DAEMON_PB_DATA_DIR}/${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',
|
||||||
|
cleanup ||
|
||||||
|
((code) => {
|
||||||
|
console.log(`Exited with ${code}`)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
ls.on('error', (err) => {
|
||||||
|
console.log(`${subdomain} had error ${err}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
await tryFetch(mkInternalUrl(port))
|
||||||
|
return ls
|
||||||
|
}
|
3
packages/daemon/src/util/internal.ts
Normal file
3
packages/daemon/src/util/internal.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const mkInternalAddress = (port: number) => `127.0.0.1:${port}`
|
||||||
|
export const mkInternalUrl = (port: number) =>
|
||||||
|
`http://${mkInternalAddress(port)}`
|
12
packages/daemon/src/util/safeCatch.ts
Normal file
12
packages/daemon/src/util/safeCatch.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export 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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
18
packages/daemon/src/util/tryFetch.ts
Normal file
18
packages/daemon/src/util/tryFetch.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import fetch from 'node-fetch'
|
||||||
|
|
||||||
|
export 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 to ${url} successful`)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error(`Could not connect to ${url}`)
|
||||||
|
setTimeout(tryFetch, 1000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
tryFetch()
|
||||||
|
})
|
21
packages/pocketbase/build.sh
Executable file
21
packages/pocketbase/build.sh
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CGO_ENABLED=0
|
||||||
|
|
||||||
|
SRC=src
|
||||||
|
TARGET=build/$PLATFORM/$VERSION
|
||||||
|
DIST=./dist
|
||||||
|
rm -rf $TARGET
|
||||||
|
mkdir -p $TARGET
|
||||||
|
mkdir -p $DIST
|
||||||
|
cp -r $SRC/* $TARGET
|
||||||
|
echo `pwd`
|
||||||
|
cd $TARGET
|
||||||
|
echo "Building ${BIN}"
|
||||||
|
echo "Fetching pocketbase version $VERSION"
|
||||||
|
go get github.com/pocketbase/pocketbase@v$VERSION
|
||||||
|
echo "Tidying modules"
|
||||||
|
go mod tidy
|
||||||
|
echo "Building ${BIN}"
|
||||||
|
go build -o ../../../$DIST/$BIN
|
||||||
|
echo "Build ${BIN} complete" `date`
|
39
packages/pocketbase/build.ts
Normal file
39
packages/pocketbase/build.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { binFor, RELEASES } from '@pockethost/common'
|
||||||
|
import { forEach } from '@s-libs/micro-dash'
|
||||||
|
import Bottleneck from 'bottleneck'
|
||||||
|
import { exec } from 'child_process'
|
||||||
|
import Listr from 'listr'
|
||||||
|
|
||||||
|
const limiter = new Bottleneck({ maxConcurrent: 10 })
|
||||||
|
|
||||||
|
const pexec = (cmd: string, cwd = __dirname) => {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
console.log(cmd)
|
||||||
|
exec(cmd, { cwd }, (err, stdout, stderr) => {
|
||||||
|
console.log(stdout)
|
||||||
|
console.error(stderr)
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tasks = new Listr([], { concurrent: true })
|
||||||
|
forEach(RELEASES, (info, platform) => {
|
||||||
|
forEach(info.versions, (version) => {
|
||||||
|
const cmd = `VERSION=${version} PLATFORM=${platform} BIN=${binFor(
|
||||||
|
platform,
|
||||||
|
version
|
||||||
|
)} ./build.sh`
|
||||||
|
tasks.add({
|
||||||
|
title: `${platform}: ${version}`,
|
||||||
|
task: () => limiter.schedule(() => pexec(cmd)),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
tasks.run().catch((err) => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
@ -1,16 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "enchanted-pocketbase",
|
"name": "@pockethost/pocketbase",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cd src && CGO_ENABLED=0 go build -o ../dist/pocketbase && echo 'Build complete' `date`",
|
"build": "tsx build.ts"
|
||||||
"build:arm64": "cd src && GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o ../dist/pocketbase && echo 'Build complete' `date`",
|
|
||||||
"build:beta:arm64": "cd src && GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o ../dist/pocketbase-beta && echo 'Build complete' `date`",
|
|
||||||
"build:386": "cd src && GOOS=linux GOARCH=386 CGO_ENABLED=0 go build -o ../dist/pocketbase && echo 'Build complete' `date`",
|
|
||||||
"build:beta:386": "cd src && GOOS=linux GOARCH=386 CGO_ENABLED=0 go build -o ../dist/pocketbase-beta && echo 'Build complete' `date`",
|
|
||||||
"watch:beta:386": "chokidar 'src/**/*' -c 'yarn build:beta:386' --initial"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chokidar-cli": "^3.0.0"
|
"chokidar-cli": "^3.0.0",
|
||||||
|
"tsx": "^3.11.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@pockethost/common": "0.0.1",
|
||||||
|
"@s-libs/micro-dash": "^14.1.0",
|
||||||
|
"@types/listr": "^0.14.4",
|
||||||
|
"@types/node": "^18.11.9",
|
||||||
|
"bottleneck": "^2.19.5",
|
||||||
|
"listr": "^0.14.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,31 +2,31 @@ module pocketbase
|
|||||||
|
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
require github.com/pocketbase/pocketbase v0.7.9
|
require github.com/pocketbase/pocketbase v0.8.0-rc1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.6 // indirect
|
github.com/AlecAivazis/survey/v2 v2.3.6 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||||
github.com/aws/aws-sdk-go v1.44.102 // indirect
|
github.com/aws/aws-sdk-go v1.44.126 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.16 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.17.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.17.7 // indirect
|
github.com/aws/aws-sdk-go-v2/config v1.17.10 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.20 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.12.23 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 // 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/accept-encoding v1.9.10 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 // 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/presigned-url v1.9.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 // indirect
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.5 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.19 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.17.1 // indirect
|
||||||
github.com/aws/smithy-go v1.13.3 // indirect
|
github.com/aws/smithy-go v1.13.4 // indirect
|
||||||
github.com/disintegration/imaging v1.6.2 // indirect
|
github.com/disintegration/imaging v1.6.2 // indirect
|
||||||
github.com/domodwyer/mailyak/v3 v3.3.4 // indirect
|
github.com/domodwyer/mailyak/v3 v3.3.4 // indirect
|
||||||
github.com/fatih/color v1.13.0 // indirect
|
github.com/fatih/color v1.13.0 // indirect
|
||||||
@ -38,48 +38,48 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/google/wire v0.5.0 // indirect
|
github.com/google/wire v0.5.0 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.5.1 // indirect
|
github.com/googleapis/gax-go/v2 v2.6.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // 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/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
github.com/mattn/go-sqlite3 v1.14.16 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/pocketbase/dbx v1.6.0 // indirect
|
github.com/pocketbase/dbx v1.7.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20220927061507-ef77025ab5aa // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/cobra v1.5.0 // indirect
|
github.com/spf13/cobra v1.6.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.23.0 // indirect
|
||||||
gocloud.dev v0.26.0 // indirect
|
gocloud.dev v0.27.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect
|
golang.org/x/crypto v0.1.0 // indirect
|
||||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 // indirect
|
golang.org/x/image v0.1.0 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
golang.org/x/mod v0.6.0 // indirect
|
||||||
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9 // indirect
|
golang.org/x/net v0.1.0 // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect
|
golang.org/x/oauth2 v0.1.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
|
golang.org/x/sys v0.1.0 // indirect
|
||||||
golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect
|
golang.org/x/term v0.1.0 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.4.0 // indirect
|
||||||
golang.org/x/time v0.0.0-20220920022843-2ce7c2934d45 // indirect
|
golang.org/x/time v0.1.0 // indirect
|
||||||
golang.org/x/tools v0.1.12 // indirect
|
golang.org/x/tools v0.2.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||||
google.golang.org/api v0.96.0 // indirect
|
google.golang.org/api v0.101.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 // indirect
|
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c // indirect
|
||||||
google.golang.org/grpc v1.49.0 // indirect
|
google.golang.org/grpc v1.50.1 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
lukechampine.com/uint128 v1.2.0 // indirect
|
lukechampine.com/uint128 v1.2.0 // indirect
|
||||||
modernc.org/cc/v3 v3.39.0 // indirect
|
modernc.org/cc/v3 v3.40.0 // indirect
|
||||||
modernc.org/ccgo/v3 v3.16.9 // indirect
|
modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8 // indirect
|
||||||
modernc.org/libc v1.19.0 // indirect
|
modernc.org/libc v1.21.4 // indirect
|
||||||
modernc.org/mathutil v1.5.0 // indirect
|
modernc.org/mathutil v1.5.0 // indirect
|
||||||
modernc.org/memory v1.4.0 // indirect
|
modernc.org/memory v1.4.0 // indirect
|
||||||
modernc.org/opt v0.1.3 // indirect
|
modernc.org/opt v0.1.3 // indirect
|
||||||
modernc.org/sqlite v1.19.1 // indirect
|
modernc.org/sqlite v1.19.3 // indirect
|
||||||
modernc.org/strutil v1.1.3 // indirect
|
modernc.org/strutil v1.1.3 // indirect
|
||||||
modernc.org/token v1.0.1 // indirect
|
modernc.org/token v1.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
103
packages/pocketbase/tsconfig.json
Normal file
103
packages/pocketbase/tsconfig.json
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||||
|
|
||||||
|
/* Projects */
|
||||||
|
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||||
|
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||||
|
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||||
|
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||||
|
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||||
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||||
|
|
||||||
|
/* Language and Environment */
|
||||||
|
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||||
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||||
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||||
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||||
|
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||||
|
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||||
|
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||||
|
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||||
|
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||||
|
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||||
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||||
|
|
||||||
|
/* Modules */
|
||||||
|
"module": "commonjs" /* Specify what module code is generated. */,
|
||||||
|
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||||
|
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||||
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||||
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
|
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||||
|
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||||
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||||
|
"resolveJsonModule": true /* Enable importing .json files. */,
|
||||||
|
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||||
|
|
||||||
|
/* JavaScript Support */
|
||||||
|
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||||
|
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||||
|
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||||
|
|
||||||
|
/* Emit */
|
||||||
|
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||||
|
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||||
|
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||||
|
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||||
|
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||||
|
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||||
|
// "removeComments": true, /* Disable emitting comments. */
|
||||||
|
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||||
|
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||||
|
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||||
|
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||||
|
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
|
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||||
|
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||||
|
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||||
|
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||||
|
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||||
|
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||||
|
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||||
|
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||||
|
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||||
|
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||||
|
|
||||||
|
/* Interop Constraints */
|
||||||
|
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||||
|
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||||
|
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||||
|
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||||
|
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||||
|
|
||||||
|
/* Type Checking */
|
||||||
|
"strict": true /* Enable all strict type-checking options. */,
|
||||||
|
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||||
|
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||||
|
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||||
|
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||||
|
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||||
|
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||||
|
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||||
|
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||||
|
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||||
|
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||||
|
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||||
|
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||||
|
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||||
|
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||||
|
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||||
|
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||||
|
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||||
|
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||||
|
|
||||||
|
/* Completeness */
|
||||||
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||||
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev --force",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
@ -30,7 +30,7 @@
|
|||||||
"@s-libs/micro-dash": "12",
|
"@s-libs/micro-dash": "12",
|
||||||
"@types/js-cookie": "^3.0.2",
|
"@types/js-cookie": "^3.0.2",
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
"pocketbase": "^0.7.0",
|
"pocketbase": "^0.8.0-rc1",
|
||||||
"random-word-slugs": "^0.1.6",
|
"random-word-slugs": "^0.1.6",
|
||||||
"sass": "^1.54.9",
|
"sass": "^1.54.9",
|
||||||
"svelte-highlight": "^6.2.1"
|
"svelte-highlight": "^6.2.1"
|
||||||
|
@ -3,11 +3,13 @@ import {
|
|||||||
assertExists,
|
assertExists,
|
||||||
createRealtimeSubscriptionManager,
|
createRealtimeSubscriptionManager,
|
||||||
type InstanceId,
|
type InstanceId,
|
||||||
type Instance_In,
|
type InstancesRecord,
|
||||||
type Instance_Out
|
type InstancesRecord_New,
|
||||||
|
type RealtimeEventHandler,
|
||||||
|
type UserRecord
|
||||||
} from '@pockethost/common'
|
} from '@pockethost/common'
|
||||||
import { keys, map } from '@s-libs/micro-dash'
|
import { keys, map } from '@s-libs/micro-dash'
|
||||||
import PocketBase, { Admin, BaseAuthStore, ClientResponseError, Record, User } from 'pocketbase'
|
import PocketBase, { Admin, BaseAuthStore, ClientResponseError, Record } from 'pocketbase'
|
||||||
import type { Unsubscriber } from 'svelte/store'
|
import type { Unsubscriber } from 'svelte/store'
|
||||||
import { safeCatch } from '../util/safeCatch'
|
import { safeCatch } from '../util/safeCatch'
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ export type AuthChangeHandler = (user: BaseAuthStore) => void
|
|||||||
export type AuthToken = string
|
export type AuthToken = string
|
||||||
export type AuthStoreProps = {
|
export type AuthStoreProps = {
|
||||||
token: AuthToken
|
token: AuthToken
|
||||||
model: User | null
|
model: UserRecord | null
|
||||||
isValid: boolean
|
isValid: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,66 +29,76 @@ export const createPocketbaseClient = (url: string) => {
|
|||||||
|
|
||||||
const { authStore } = client
|
const { authStore } = client
|
||||||
|
|
||||||
const user = () => authStore.model
|
const user = () => authStore.model as AuthStoreProps['model']
|
||||||
|
|
||||||
const isLoggedIn = () => authStore.isValid
|
const isLoggedIn = () => authStore.isValid
|
||||||
|
|
||||||
const logOut = () => authStore.clear()
|
const logOut = () => authStore.clear()
|
||||||
|
|
||||||
const createUser = safeCatch(`createUser`, (email: string, password: string) =>
|
const createUser = safeCatch(`createUser`, (email: string, password: string) =>
|
||||||
client.users.create({
|
client
|
||||||
email,
|
.collection('users')
|
||||||
password,
|
.create({
|
||||||
passwordConfirm: password
|
email,
|
||||||
})
|
password,
|
||||||
|
passwordConfirm: password
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
console.log(`Sending verification email to ${email}`)
|
||||||
|
return client.collection('users').requestVerification(email)
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
const authViaEmail = safeCatch(`authViaEmail`, (email: string, password: string) =>
|
const authViaEmail = safeCatch(`authViaEmail`, (email: string, password: string) =>
|
||||||
client.users.authViaEmail(email, password)
|
client.collection('users').authWithPassword(email, password)
|
||||||
)
|
)
|
||||||
|
|
||||||
const refreshAuthToken = safeCatch(`refreshAuthToken`, () => client.users.refresh())
|
const refreshAuthToken = safeCatch(`refreshAuthToken`, () =>
|
||||||
|
client.collection('users').authRefresh()
|
||||||
|
)
|
||||||
|
|
||||||
const createInstance = safeCatch(
|
const createInstance = safeCatch(
|
||||||
`createInstance`,
|
`createInstance`,
|
||||||
(payload: Instance_In): Promise<Instance_Out> => {
|
(payload: InstancesRecord_New): Promise<InstancesRecord> => {
|
||||||
return client.records.create('instances', payload).then((r) => r as unknown as Instance_Out)
|
return client.collection('instances').create<InstancesRecord>(payload)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const getInstanceById = safeCatch(
|
const getInstanceById = safeCatch(
|
||||||
`getInstanceById`,
|
`getInstanceById`,
|
||||||
(id: InstanceId): Promise<Instance_Out | undefined> =>
|
(id: InstanceId): Promise<InstancesRecord | undefined> =>
|
||||||
client.records.getOne('instances', id).then((r) => r as unknown as Instance_Out)
|
client.collection('instances').getOne<InstancesRecord>(id)
|
||||||
)
|
)
|
||||||
|
|
||||||
const subscribe = createRealtimeSubscriptionManager(client)
|
const { subscribeOne } = createRealtimeSubscriptionManager(client)
|
||||||
|
|
||||||
const watchInstanceById = (id: InstanceId, cb: (rec: Instance_Out) => void): Unsubscriber => {
|
const watchInstanceById = (
|
||||||
const slug = `instances/${id}`
|
id: InstanceId,
|
||||||
getInstanceById(id).then((v) => {
|
cb: RealtimeEventHandler<InstancesRecord>
|
||||||
if (!v) return
|
): Unsubscriber => {
|
||||||
cb(v)
|
getInstanceById(id).then((record) => {
|
||||||
|
console.log(`Got instnace`, record)
|
||||||
|
assertExists(record, `Expected instance ${id} here`)
|
||||||
|
cb({ action: 'init', record })
|
||||||
})
|
})
|
||||||
return subscribe(slug, cb)
|
return subscribeOne('instances', id, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAllInstancesById = safeCatch(`getAllInstancesById`, async () =>
|
const getAllInstancesById = safeCatch(`getAllInstancesById`, async () =>
|
||||||
(
|
(
|
||||||
await client.records.getFullList('instances').catch((e) => {
|
await client
|
||||||
console.error(`getAllInstancesById failed with ${e}`)
|
.collection('instances')
|
||||||
throw e
|
.getFullList()
|
||||||
})
|
.catch((e) => {
|
||||||
|
console.error(`getAllInstancesById failed with ${e}`)
|
||||||
|
throw e
|
||||||
|
})
|
||||||
).reduce((c, v) => {
|
).reduce((c, v) => {
|
||||||
c[v.id] = v
|
c[v.id] = v
|
||||||
return c
|
return c
|
||||||
}, {} as Record)
|
}, {} as Record)
|
||||||
)
|
)
|
||||||
|
|
||||||
const setInstance = safeCatch(`setInstance`, (instanceId: InstanceId, fields: Instance_In) => {
|
|
||||||
return client.records.update('instances', instanceId, fields)
|
|
||||||
})
|
|
||||||
|
|
||||||
const parseError = (e: Error): string[] => {
|
const parseError = (e: Error): string[] => {
|
||||||
if (!(e instanceof ClientResponseError)) return [e.message]
|
if (!(e instanceof ClientResponseError)) return [e.message]
|
||||||
if (e.data.message && keys(e.data.data).length === 0) return [e.data.message]
|
if (e.data.message && keys(e.data.data).length === 0) return [e.data.message]
|
||||||
@ -96,13 +108,14 @@ export const createPocketbaseClient = (url: string) => {
|
|||||||
const resendVerificationEmail = safeCatch(`resendVerificationEmail`, async () => {
|
const resendVerificationEmail = safeCatch(`resendVerificationEmail`, async () => {
|
||||||
const user = client.authStore.model
|
const user = client.authStore.model
|
||||||
assertExists(user, `Login required`)
|
assertExists(user, `Login required`)
|
||||||
await client.users.requestVerification(user.email)
|
await client.collection('users').requestVerification(user.email)
|
||||||
})
|
})
|
||||||
|
|
||||||
const getAuthStoreProps = (): AuthStoreProps => {
|
const getAuthStoreProps = (): AuthStoreProps => {
|
||||||
const { token, model, isValid } = client.authStore
|
const { token, model, isValid } = client.authStore as AuthStoreProps
|
||||||
// console.log(`curent authstore`, { token, model, isValid })
|
// console.log(`curent authstore`, { token, model, isValid })
|
||||||
if (model instanceof Admin) throw new Error(`Admin models not supported`)
|
if (model instanceof Admin) throw new Error(`Admin models not supported`)
|
||||||
|
if (model && !model.email) throw new Error(`Expected model to be a user here`)
|
||||||
return {
|
return {
|
||||||
token,
|
token,
|
||||||
model,
|
model,
|
||||||
@ -132,7 +145,10 @@ export const createPocketbaseClient = (url: string) => {
|
|||||||
* out of date, or fields in the user record may have changed in the backend.
|
* out of date, or fields in the user record may have changed in the backend.
|
||||||
*/
|
*/
|
||||||
refreshAuthToken()
|
refreshAuthToken()
|
||||||
.catch(() => {})
|
.catch((e) => {
|
||||||
|
console.error(`Clearing auth store: ${e}`)
|
||||||
|
client.authStore.clear()
|
||||||
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
fireAuthChange(getAuthStoreProps())
|
fireAuthChange(getAuthStoreProps())
|
||||||
})
|
})
|
||||||
@ -154,7 +170,7 @@ export const createPocketbaseClient = (url: string) => {
|
|||||||
unsub()
|
unsub()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const _check = safeCatch(`_checkVerified`, () => client.users.refresh())
|
const _check = safeCatch(`_checkVerified`, refreshAuthToken)
|
||||||
setTimeout(_check, 1000)
|
setTimeout(_check, 1000)
|
||||||
|
|
||||||
// FIXME - THIS DOES NOT WORK, WE HAVE TO POLL INSTEAD. FIX IN V0.8
|
// FIXME - THIS DOES NOT WORK, WE HAVE TO POLL INSTEAD. FIX IN V0.8
|
||||||
@ -169,7 +185,6 @@ export const createPocketbaseClient = (url: string) => {
|
|||||||
return {
|
return {
|
||||||
getAuthStoreProps,
|
getAuthStoreProps,
|
||||||
parseError,
|
parseError,
|
||||||
subscribe,
|
|
||||||
getInstanceById,
|
getInstanceById,
|
||||||
createInstance,
|
createInstance,
|
||||||
authViaEmail,
|
authViaEmail,
|
||||||
@ -180,7 +195,6 @@ export const createPocketbaseClient = (url: string) => {
|
|||||||
user,
|
user,
|
||||||
watchInstanceById,
|
watchInstanceById,
|
||||||
getAllInstancesById,
|
getAllInstancesById,
|
||||||
setInstance,
|
|
||||||
resendVerificationEmail
|
resendVerificationEmail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,25 +5,27 @@
|
|||||||
import { PUBLIC_PB_PROTOCOL } from '$env/static/public'
|
import { PUBLIC_PB_PROTOCOL } from '$env/static/public'
|
||||||
import { PUBLIC_PB_DOMAIN } from '$src/env'
|
import { PUBLIC_PB_DOMAIN } from '$src/env'
|
||||||
import { client } from '$src/pocketbase'
|
import { client } from '$src/pocketbase'
|
||||||
|
import { humanVersion, type InstancesRecord } from '@pockethost/common'
|
||||||
import { assertExists } from '@pockethost/common/src/assert'
|
import { assertExists } from '@pockethost/common/src/assert'
|
||||||
import type { Instance_Out } from '@pockethost/common/src/schema'
|
|
||||||
import { onDestroy, onMount } from 'svelte'
|
import { onDestroy, onMount } from 'svelte'
|
||||||
import type { Unsubscriber } from 'svelte/store'
|
import type { Unsubscriber } from 'svelte/store'
|
||||||
|
|
||||||
const { instanceId } = $page.params
|
const { instanceId } = $page.params
|
||||||
|
|
||||||
let instance: Instance_Out | undefined
|
let instance: InstancesRecord | undefined
|
||||||
|
|
||||||
let url: string
|
let url: string
|
||||||
let code: string = ''
|
let code: string = ''
|
||||||
let unsub: Unsubscriber = () => {}
|
let unsub: Unsubscriber = () => {}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(async () => {
|
||||||
const { watchInstanceById } = client()
|
const { watchInstanceById } = client()
|
||||||
unsub = watchInstanceById(instanceId, (r) => {
|
unsub = watchInstanceById(instanceId, (r) => {
|
||||||
instance = r
|
console.log(`Handling instance update`, r)
|
||||||
assertExists(instance, `Expected instance here`)
|
const { action, record } = r
|
||||||
const { subdomain } = instance
|
instance = record
|
||||||
|
assertExists(record, `Expected instance here`)
|
||||||
|
const { subdomain } = record
|
||||||
url = `${PUBLIC_PB_PROTOCOL}://${subdomain}.${PUBLIC_PB_DOMAIN}`
|
url = `${PUBLIC_PB_PROTOCOL}://${subdomain}.${PUBLIC_PB_DOMAIN}`
|
||||||
code = `const url = '${url}'\nconst client = new PocketBase(url)`
|
code = `const url = '${url}'\nconst client = new PocketBase(url)`
|
||||||
})
|
})
|
||||||
@ -50,6 +52,10 @@
|
|||||||
JavaScript:
|
JavaScript:
|
||||||
<CodeSample {code} />
|
<CodeSample {code} />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
Running {instance.platform}
|
||||||
|
{humanVersion(instance.platform, instance.version)}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="text-center py-5">
|
<div class="text-center py-5">
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
import { PUBLIC_PB_DOMAIN } from '$src/env'
|
import { PUBLIC_PB_DOMAIN } from '$src/env'
|
||||||
import { client } from '$src/pocketbase'
|
import { client } from '$src/pocketbase'
|
||||||
import { createCleanupManagerSync } from '$util/CleanupManager'
|
import { createCleanupManagerSync } from '$util/CleanupManager'
|
||||||
import type { Instance_Out, Instance_Out_ByIdCollection } from '@pockethost/common/src/schema'
|
import { humanVersion, type InstanceRecordById, type InstancesRecord } from '@pockethost/common'
|
||||||
import { forEach, values } from '@s-libs/micro-dash'
|
import { forEach, values } from '@s-libs/micro-dash'
|
||||||
import { onDestroy, onMount } from 'svelte'
|
import { onDestroy, onMount } from 'svelte'
|
||||||
import { fade } from 'svelte/transition'
|
import { fade } from 'svelte/transition'
|
||||||
@ -13,18 +13,18 @@
|
|||||||
// Wait for the instance call to complete before rendering the UI
|
// Wait for the instance call to complete before rendering the UI
|
||||||
let hasPageLoaded = false
|
let hasPageLoaded = false
|
||||||
|
|
||||||
let apps: Instance_Out_ByIdCollection = {}
|
let apps: InstanceRecordById = {}
|
||||||
|
|
||||||
// This will update when the `apps` value changes
|
// This will update when the `apps` value changes
|
||||||
$: isFirstApplication = values(apps).length === 0
|
$: isFirstApplication = values(apps).length === 0
|
||||||
|
|
||||||
let appsArray: Instance_Out[]
|
let appsArray: InstancesRecord[]
|
||||||
$: {
|
$: {
|
||||||
appsArray = values(apps)
|
appsArray = values(apps)
|
||||||
}
|
}
|
||||||
const cm = createCleanupManagerSync()
|
const cm = createCleanupManagerSync()
|
||||||
let _touch = 0 // This is a fake var because without it the watcher callback will not update UI when the apps object changes
|
let _touch = 0 // This is a fake var because without it the watcher callback will not update UI when the apps object changes
|
||||||
const _update = (_apps: Instance_Out_ByIdCollection) => {
|
const _update = (_apps: InstanceRecordById) => {
|
||||||
apps = _apps
|
apps = _apps
|
||||||
_touch++
|
_touch++
|
||||||
}
|
}
|
||||||
@ -38,7 +38,8 @@
|
|||||||
const instanceId = app.id
|
const instanceId = app.id
|
||||||
|
|
||||||
const unsub = watchInstanceById(instanceId, (r) => {
|
const unsub = watchInstanceById(instanceId, (r) => {
|
||||||
_update({ ...apps, [r.id]: r })
|
const { action, record } = r
|
||||||
|
_update({ ...apps, [record.id]: record })
|
||||||
})
|
})
|
||||||
cm.add(unsub)
|
cm.add(unsub)
|
||||||
})
|
})
|
||||||
@ -74,6 +75,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 class="mb-4 font-monospace">{app.subdomain}</h2>
|
<h2 class="mb-4 font-monospace">{app.subdomain}</h2>
|
||||||
|
Running {app.platform}
|
||||||
|
{humanVersion(app.platform, app.version)}
|
||||||
|
|
||||||
<div class="d-flex justify-content-around">
|
<div class="d-flex justify-content-around">
|
||||||
<a href={`/app/instances/${app.id}`} class="btn btn-light">
|
<a href={`/app/instances/${app.id}`} class="btn btn-light">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { goto } from '$app/navigation'
|
import { goto } from '$app/navigation'
|
||||||
import { client } from '$src/pocketbase'
|
import { client } from '$src/pocketbase'
|
||||||
import { InstanceStatus } from '@pockethost/common'
|
import { InstanceStatus, LATEST_PLATFORM, USE_LATEST_VERSION } from '@pockethost/common'
|
||||||
|
|
||||||
export type FormErrorHandler = (value: string) => void
|
export type FormErrorHandler = (value: string) => void
|
||||||
|
|
||||||
@ -83,7 +83,9 @@ export const handleCreateNewInstance = async (
|
|||||||
const record = await createInstance({
|
const record = await createInstance({
|
||||||
subdomain: instanceName,
|
subdomain: instanceName,
|
||||||
uid: id,
|
uid: id,
|
||||||
status: InstanceStatus.Idle
|
status: InstanceStatus.Idle,
|
||||||
|
platform: LATEST_PLATFORM,
|
||||||
|
version: USE_LATEST_VERSION
|
||||||
})
|
})
|
||||||
|
|
||||||
await goto(`/app/instances/${record.id}`)
|
await goto(`/app/instances/${record.id}`)
|
||||||
|
18
readme.md
18
readme.md
@ -93,9 +93,9 @@ git clone git@github.com:benallfree/pockethost.git
|
|||||||
cd pockethost/docker
|
cd pockethost/docker
|
||||||
cp .env-template-dev .env.local # Edit as needed - defaults should work
|
cp .env-template-dev .env.local # Edit as needed - defaults should work
|
||||||
cd ..
|
cd ..
|
||||||
docker-compose -f docker/docker-compose-dev.yaml build
|
docker-compose -f docker/build.yaml up --remove-orphans
|
||||||
docker-compose -f docker/docker-compose-dev.yaml --profile=build up --remove-orphans
|
docker-compose -f docker/migrate.yaml up --remove-orphans
|
||||||
docker-compose -f docker/docker-compose-dev.yaml --profile=serve up --remove-orphans
|
docker-compose -f docker/dev.yaml up --remove-orphans
|
||||||
open https://pockethost.test
|
open https://pockethost.test
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -108,10 +108,9 @@ git clone git@github.com:benallfree/pockethost.git
|
|||||||
cd pockethost/docker
|
cd pockethost/docker
|
||||||
cp .env-template-prod .env.local # Edit as needed - defaults should work
|
cp .env-template-prod .env.local # Edit as needed - defaults should work
|
||||||
cd ..
|
cd ..
|
||||||
docker-compose -f docker/docker-compose-prod.yaml build
|
docker-compose -f docker/build.yaml up --remove-orphans
|
||||||
# Use 'buildbox' to test your build before launching service
|
docker-compose -f docker/migrate.yaml up --remove-orphans
|
||||||
docker-compose -f docker/docker-compose-prod.yaml --profile=build up --remove-orphans
|
docker-compose -f docker/prod.yaml up --remove-orphans
|
||||||
docker-compose -f docker/docker-compose-prod.yaml --profile=serve up --remove-orphans
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**2. Refresh Certbot**
|
**2. Refresh Certbot**
|
||||||
@ -131,9 +130,10 @@ open https://pockethost.io
|
|||||||
|
|
||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
**next**
|
**0.4.0**
|
||||||
|
|
||||||
- [ ]
|
- [x] PocketBase 0.8 support
|
||||||
|
- [x] Introduced "platforms" concept for version control
|
||||||
|
|
||||||
**0.3.2**
|
**0.3.2**
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user