mirror of
https://github.com/pockethost/pockethost.git
synced 2025-03-30 15:08:30 +00:00
feat: native PB migrations
This commit is contained in:
parent
1a23f5b2fd
commit
17ab6c5fa7
@ -3,6 +3,7 @@ PUBLIC_APP_DOMAIN=pockethost.test
|
||||
PUBLIC_APP_DB=pockethost-central
|
||||
DAEMON_PB_BIN_DIR=`pwd`/packages/pocketbase/dist
|
||||
DAEMON_PB_DATA_DIR=`pwd`/.data
|
||||
DAEMON_PB_MIGRATIONS_DIR=`pwd`/packages/daemon/migrations
|
||||
DAEMON_PB_USERNAME=admin@pockethost.test
|
||||
DAEMON_PB_PASSWORD=admin@pockethost.test
|
||||
DAEMON_PB_PORT=8090
|
||||
|
@ -21,8 +21,6 @@
|
||||
"pm2:proxy": "cd packages/proxy && yarn pm2",
|
||||
"pm2:www": "cd packages/pockethost.io && yarn pm2",
|
||||
"pm2:daemon": "cd packages/daemon && yarn pm2",
|
||||
"migrate": "yarn migrate:daemon",
|
||||
"migrate:daemon": "cd packages/daemon && yarn migrate",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"workspaces": {
|
||||
@ -50,4 +48,4 @@
|
||||
"dependencies": {
|
||||
"postinstall-postinstall": "^2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
492
packages/daemon/migrations/1686178611_collections_snapshot.js
Normal file
492
packages/daemon/migrations/1686178611_collections_snapshot.js
Normal file
@ -0,0 +1,492 @@
|
||||
migrate((db) => {
|
||||
const snapshot = [
|
||||
{
|
||||
"id": "etae8tuiaxl6xfv",
|
||||
"created": "2022-10-20 08:51:44.195Z",
|
||||
"updated": "2023-06-07 22:41:11.725Z",
|
||||
"name": "instances",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"system": false,
|
||||
"id": "qdtuuld1",
|
||||
"name": "subdomain",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": true,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": 50,
|
||||
"pattern": "^[a-z][\\-a-z]+$"
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "rbj14krn",
|
||||
"name": "uid",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "systemprofiles0",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "c2y74d7h",
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "yxby5r6b",
|
||||
"name": "platform",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "4ydffkv3",
|
||||
"name": "version",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "1arlklqq",
|
||||
"name": "secondsThisMonth",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "66vjgzcg",
|
||||
"name": "isBackupAllowed",
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "qew2o2d6",
|
||||
"name": "currentWorkerBundleId",
|
||||
"type": "text",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "3yu1db4p",
|
||||
"name": "secrets",
|
||||
"type": "json",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
"CREATE UNIQUE INDEX \"idx_unique_qdtuuld1\" on \"instances\" (\"subdomain\")"
|
||||
],
|
||||
"listRule": "uid=@request.auth.id",
|
||||
"viewRule": "uid = @request.auth.id",
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "systemprofiles0",
|
||||
"created": "2022-10-31 21:31:52.175Z",
|
||||
"updated": "2023-06-07 22:41:11.723Z",
|
||||
"name": "users",
|
||||
"type": "auth",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"system": false,
|
||||
"id": "pbfieldname",
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "pbfieldavatar",
|
||||
"name": "avatar",
|
||||
"type": "file",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"maxSelect": 1,
|
||||
"maxSize": 5242880,
|
||||
"mimeTypes": [
|
||||
"image/jpg",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/svg+xml",
|
||||
"image/gif"
|
||||
],
|
||||
"thumbs": null,
|
||||
"protected": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "id = @request.auth.id",
|
||||
"viewRule": "id = @request.auth.id",
|
||||
"createRule": "",
|
||||
"updateRule": "id = @request.auth.id",
|
||||
"deleteRule": null,
|
||||
"options": {
|
||||
"allowEmailAuth": true,
|
||||
"allowOAuth2Auth": true,
|
||||
"allowUsernameAuth": false,
|
||||
"exceptEmailDomains": null,
|
||||
"manageRule": null,
|
||||
"minPasswordLength": 8,
|
||||
"onlyEmailDomains": null,
|
||||
"requireEmail": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aiw8te7y7atklwn",
|
||||
"created": "2022-11-04 13:54:23.745Z",
|
||||
"updated": "2023-06-07 22:41:11.723Z",
|
||||
"name": "invocations",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"system": false,
|
||||
"id": "st9ydrbo",
|
||||
"name": "instanceId",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "etae8tuiaxl6xfv",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "av4mpuyh",
|
||||
"name": "startedAt",
|
||||
"type": "date",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": "",
|
||||
"max": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "fnwatixg",
|
||||
"name": "endedAt",
|
||||
"type": "date",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": "",
|
||||
"max": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "awjozhbn",
|
||||
"name": "pid",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "vdkfqege",
|
||||
"name": "totalSeconds",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "v7s41iokt1vizxd",
|
||||
"created": "2022-11-06 17:23:25.947Z",
|
||||
"updated": "2023-06-07 22:41:11.723Z",
|
||||
"name": "rpc",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"system": false,
|
||||
"id": "yv38czcf",
|
||||
"name": "userId",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "systemprofiles0",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "tgvaxwfv",
|
||||
"name": "payload",
|
||||
"type": "json",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "zede8pci",
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "nd7cwqmn",
|
||||
"name": "result",
|
||||
"type": "json",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "2hlrcx5j",
|
||||
"name": "cmd",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "userId = @request.auth.id",
|
||||
"viewRule": "userId = @request.auth.id",
|
||||
"createRule": "userId = @request.auth.id && status='' && result='' && cmd ?= @collection.rpc_cmds.name",
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "72clb6v41bzsay9",
|
||||
"created": "2022-11-09 15:23:20.313Z",
|
||||
"updated": "2023-06-07 22:41:11.723Z",
|
||||
"name": "backups",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"system": false,
|
||||
"id": "someqtjw",
|
||||
"name": "message",
|
||||
"type": "text",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "jk4zwiaj",
|
||||
"name": "instanceId",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "etae8tuiaxl6xfv",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "wsy3l5gm",
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "gmkrc5d9",
|
||||
"name": "bytes",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "4lmammjz",
|
||||
"name": "platform",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "fheqxmbj",
|
||||
"name": "version",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "cinbmdwe",
|
||||
"name": "progress",
|
||||
"type": "json",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "@request.auth.id = instanceId.uid",
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "enp8mrv5ewtrltj",
|
||||
"created": "2023-01-06 10:21:51.659Z",
|
||||
"updated": "2023-06-07 22:41:11.725Z",
|
||||
"name": "rpc_cmds",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"system": false,
|
||||
"id": "jbostfhp",
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": true,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
"CREATE UNIQUE INDEX \"idx_unique_jbostfhp\" on \"rpc_cmds\" (\"name\")"
|
||||
],
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
}
|
||||
];
|
||||
|
||||
const collections = snapshot.map((item) => new Collection(item));
|
||||
|
||||
return Dao(db).importCollections(collections, true, null);
|
||||
}, (db) => {
|
||||
return null;
|
||||
})
|
@ -21,6 +21,19 @@ export const DAEMON_PB_PASSWORD = (() => {
|
||||
})()
|
||||
export const DAEMON_PB_PORT_BASE = envi('DAEMON_PB_PORT_BASE', 8090)
|
||||
export const DAEMON_PB_IDLE_TTL = envi('DAEMON_PB_IDLE_TTL', 5000)
|
||||
export const DAEMON_PB_MIGRATIONS_DIR = (() => {
|
||||
const v = env('DAEMON_PB_MIGRATIONS_DIR')
|
||||
if (!v) {
|
||||
throw new Error(
|
||||
`DAEMON_PB_MIGRATIONS_DIR (${v}) environment variable must be specified`
|
||||
)
|
||||
}
|
||||
if (!existsSync(v)) {
|
||||
throw new Error(`DAEMON_PB_MIGRATIONS_DIR (${v}) path must exist`)
|
||||
}
|
||||
return v
|
||||
})()
|
||||
|
||||
export const DAEMON_PB_DATA_DIR = (() => {
|
||||
const v = env('DAEMON_PB_DATA_DIR')
|
||||
if (!v) {
|
||||
@ -68,6 +81,7 @@ console.log({
|
||||
PUBLIC_APP_DB,
|
||||
DAEMON_PB_USERNAME,
|
||||
DAEMON_PB_PASSWORD,
|
||||
DAEMON_PB_MIGRATIONS_DIR,
|
||||
DAEMON_PB_SEMVER,
|
||||
DENO_PATH,
|
||||
PH_FTP_PASV_IP,
|
||||
|
@ -1,49 +0,0 @@
|
||||
import { DEBUG, PH_BIN_CACHE, PUBLIC_APP_DB } from '$constants'
|
||||
import { pocketbase } from '$services'
|
||||
import { InstanceStatus, logger, safeCatch } from '@pockethost/common'
|
||||
import { schema } from './schema'
|
||||
import { withInstance } from './withInstance'
|
||||
;(async () => {
|
||||
const { info } = logger({ debug: DEBUG }).create('migrate')
|
||||
|
||||
const pbService = await pocketbase({
|
||||
cachePath: PH_BIN_CACHE,
|
||||
checkIntervalMs: 5 * 60 * 1000,
|
||||
})
|
||||
|
||||
safeCatch(`root`, async () => {
|
||||
// await backupInstance(
|
||||
// PUBLIC_PB_SUBDOMAIN,
|
||||
// `${+new Date()}`,
|
||||
// async (progress) => {
|
||||
// dbg(progress)
|
||||
// }
|
||||
// )
|
||||
|
||||
info(`Upgrading`)
|
||||
const upgradeProcess = await pbService.spawn({
|
||||
command: 'upgrade',
|
||||
slug: PUBLIC_APP_DB,
|
||||
})
|
||||
await upgradeProcess.exited
|
||||
|
||||
await withInstance(async (client) => {
|
||||
await client.applySchema(schema)
|
||||
|
||||
await client.updateInstances((instance) => {
|
||||
const version = (() => {
|
||||
if (instance.platform === 'ermine') return '~0.7.0'
|
||||
if (instance.platform === 'lollipop') return '~0.10.0'
|
||||
return pbService.getLatestVersion()
|
||||
})()
|
||||
console.log(`Updating instance ${instance.id} to ${version}`)
|
||||
return {
|
||||
status: InstanceStatus.Idle,
|
||||
version,
|
||||
}
|
||||
})
|
||||
})
|
||||
console.log(`All instances updated`)
|
||||
})()
|
||||
pbService.shutdown()
|
||||
})()
|
@ -1,357 +0,0 @@
|
||||
import { Collection, SchemaField } from 'pocketbase'
|
||||
|
||||
export type Collection_Serialized = Omit<Partial<Collection>, 'schema'> & {
|
||||
schema: Array<Partial<SchemaField>>
|
||||
}
|
||||
|
||||
export const schema: Collection_Serialized[] = [
|
||||
{
|
||||
id: 'etae8tuiaxl6xfv',
|
||||
name: 'instances',
|
||||
type: 'base',
|
||||
system: false,
|
||||
schema: [
|
||||
{
|
||||
id: 'qdtuuld1',
|
||||
name: 'subdomain',
|
||||
type: 'text',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: true,
|
||||
options: {
|
||||
min: null,
|
||||
max: 50,
|
||||
pattern: '^[a-z][\\-a-z]+$',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'rbj14krn',
|
||||
name: 'uid',
|
||||
type: 'relation',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
maxSelect: 1,
|
||||
collectionId: '_pb_users_auth_',
|
||||
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: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '1arlklqq',
|
||||
name: 'secondsThisMonth',
|
||||
type: 'number',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '66vjgzcg',
|
||||
name: 'isBackupAllowed',
|
||||
type: 'bool',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {},
|
||||
},
|
||||
],
|
||||
listRule: 'uid=@request.auth.id',
|
||||
viewRule: 'uid = @request.auth.id',
|
||||
createRule: null,
|
||||
updateRule: null,
|
||||
deleteRule: null,
|
||||
options: {},
|
||||
},
|
||||
{
|
||||
id: 'aiw8te7y7atklwn',
|
||||
name: 'invocations',
|
||||
type: 'base',
|
||||
system: false,
|
||||
schema: [
|
||||
{
|
||||
id: 'st9ydrbo',
|
||||
name: 'instanceId',
|
||||
type: 'relation',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
maxSelect: 1,
|
||||
collectionId: 'etae8tuiaxl6xfv',
|
||||
cascadeDelete: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'av4mpuyh',
|
||||
name: 'startedAt',
|
||||
type: 'date',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
min: '',
|
||||
max: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'fnwatixg',
|
||||
name: 'endedAt',
|
||||
type: 'date',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {
|
||||
min: '',
|
||||
max: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'awjozhbn',
|
||||
name: 'pid',
|
||||
type: 'number',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'vdkfqege',
|
||||
name: 'totalSeconds',
|
||||
type: 'number',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
listRule: null,
|
||||
viewRule: null,
|
||||
createRule: null,
|
||||
updateRule: null,
|
||||
deleteRule: null,
|
||||
options: {},
|
||||
},
|
||||
{
|
||||
id: 'v7s41iokt1vizxd',
|
||||
name: 'rpc',
|
||||
type: 'base',
|
||||
system: false,
|
||||
schema: [
|
||||
{
|
||||
id: 'yv38czcf',
|
||||
name: 'userId',
|
||||
type: 'relation',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
maxSelect: 1,
|
||||
collectionId: '_pb_users_auth_',
|
||||
cascadeDelete: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'tgvaxwfv',
|
||||
name: 'payload',
|
||||
type: 'json',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {},
|
||||
},
|
||||
{
|
||||
id: 'zede8pci',
|
||||
name: 'status',
|
||||
type: 'text',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
pattern: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'nd7cwqmn',
|
||||
name: 'result',
|
||||
type: 'json',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {},
|
||||
},
|
||||
{
|
||||
id: '2hlrcx5j',
|
||||
name: 'cmd',
|
||||
type: 'text',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
pattern: '',
|
||||
},
|
||||
},
|
||||
],
|
||||
listRule: 'userId = @request.auth.id',
|
||||
viewRule: 'userId = @request.auth.id',
|
||||
createRule:
|
||||
"userId = @request.auth.id && status='' && (cmd='backup-instance' || cmd='restore-instance' || cmd='create-instance') && payload!='' && result=''",
|
||||
updateRule: null,
|
||||
deleteRule: null,
|
||||
options: {},
|
||||
},
|
||||
{
|
||||
id: '72clb6v41bzsay9',
|
||||
name: 'backups',
|
||||
type: 'base',
|
||||
system: false,
|
||||
schema: [
|
||||
{
|
||||
id: 'someqtjw',
|
||||
name: 'message',
|
||||
type: 'text',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
pattern: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'jk4zwiaj',
|
||||
name: 'instanceId',
|
||||
type: 'relation',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
maxSelect: 1,
|
||||
collectionId: 'etae8tuiaxl6xfv',
|
||||
cascadeDelete: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'wsy3l5gm',
|
||||
name: 'status',
|
||||
type: 'text',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
pattern: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'gmkrc5d9',
|
||||
name: 'bytes',
|
||||
type: 'number',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '4lmammjz',
|
||||
name: 'platform',
|
||||
type: 'text',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
pattern: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'fheqxmbj',
|
||||
name: 'version',
|
||||
type: 'text',
|
||||
system: false,
|
||||
required: true,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
pattern: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'cinbmdwe',
|
||||
name: 'progress',
|
||||
type: 'json',
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
options: {},
|
||||
},
|
||||
],
|
||||
listRule: '@request.auth.id = instanceId.uid',
|
||||
viewRule: null,
|
||||
createRule: null,
|
||||
updateRule: null,
|
||||
deleteRule: null,
|
||||
options: {},
|
||||
},
|
||||
]
|
||||
|
||||
console.log(JSON.stringify(schema))
|
@ -1,45 +0,0 @@
|
||||
import {
|
||||
DAEMON_PB_PASSWORD,
|
||||
DAEMON_PB_USERNAME,
|
||||
PUBLIC_APP_DB,
|
||||
PUBLIC_APP_DOMAIN,
|
||||
PUBLIC_APP_PROTOCOL,
|
||||
} from '$constants'
|
||||
import { createPbClient, pocketbase, PocketbaseClientApi } from '$services'
|
||||
import { logger, safeCatch } from '@pockethost/common'
|
||||
|
||||
export const withInstance = safeCatch(
|
||||
`withInstance`,
|
||||
async (cb: (client: PocketbaseClientApi) => Promise<void>) => {
|
||||
const { info, error } = logger().create('withInstance')
|
||||
|
||||
// Add `platform` and `bin` required columns (migrate db json)
|
||||
try {
|
||||
const mainProcess = await (
|
||||
await pocketbase()
|
||||
).spawn({
|
||||
command: 'serve',
|
||||
slug: PUBLIC_APP_DB,
|
||||
})
|
||||
|
||||
try {
|
||||
const { url } = mainProcess
|
||||
const client = createPbClient(url)
|
||||
await client.adminAuthViaEmail(DAEMON_PB_USERNAME, DAEMON_PB_PASSWORD)
|
||||
await cb(client)
|
||||
} catch (e) {
|
||||
error(
|
||||
`***WARNING*** CANNOT AUTHENTICATE TO ${PUBLIC_APP_PROTOCOL}://${PUBLIC_APP_DB}.${PUBLIC_APP_DOMAIN}/_/`
|
||||
)
|
||||
error(`***WARNING*** LOG IN MANUALLY, ADJUST .env, AND RESTART DOCKER`)
|
||||
process.exit(-1)
|
||||
} finally {
|
||||
info(`Exiting process`)
|
||||
mainProcess.kill()
|
||||
await mainProcess.exited
|
||||
}
|
||||
} catch (e) {
|
||||
error(`${e}`)
|
||||
}
|
||||
}
|
||||
)
|
@ -50,8 +50,22 @@ global.EventSource = require('eventsource')
|
||||
/**
|
||||
* Launch central database
|
||||
*/
|
||||
{
|
||||
info(`Migrating mothership`)
|
||||
await (
|
||||
await pbService.spawn({
|
||||
command: 'migrate',
|
||||
isMothership: true,
|
||||
version: DAEMON_PB_SEMVER,
|
||||
slug: PUBLIC_APP_DB,
|
||||
})
|
||||
).exited
|
||||
info(`Migrating done`)
|
||||
}
|
||||
info(`Serving`)
|
||||
const { url } = await pbService.spawn({
|
||||
command: 'serve',
|
||||
isMothership: true,
|
||||
version: DAEMON_PB_SEMVER,
|
||||
slug: PUBLIC_APP_DB,
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DAEMON_PB_DATA_DIR } from '$constants'
|
||||
import { DAEMON_PB_DATA_DIR, DAEMON_PB_MIGRATIONS_DIR } from '$constants'
|
||||
import {
|
||||
downloadAndExtract,
|
||||
mkInternalAddress,
|
||||
@ -22,12 +22,13 @@ import { join } from 'path'
|
||||
import { maxSatisfying, rsort } from 'semver'
|
||||
import { AsyncReturnType } from 'type-fest'
|
||||
|
||||
export type PocketbaseCommand = 'serve' | 'upgrade'
|
||||
export type PocketbaseCommand = 'serve' | 'migrate'
|
||||
export type SpawnConfig = {
|
||||
command: PocketbaseCommand
|
||||
slug: string
|
||||
version?: string
|
||||
port?: number
|
||||
isMothership?: boolean
|
||||
onUnexpectedStop?: (code: number | null) => void
|
||||
}
|
||||
export type PocketbaseServiceApi = AsyncReturnType<
|
||||
@ -138,11 +139,14 @@ export const createPocketbaseService = async (
|
||||
const _cfg: Required<SpawnConfig> = {
|
||||
version: maxVersion,
|
||||
port: await getPort(),
|
||||
isMothership: false,
|
||||
onUnexpectedStop: (code) => {
|
||||
dbg(`Unexpected stop default handler. Exit code: ${code}`)
|
||||
},
|
||||
...cfg,
|
||||
}
|
||||
const { version, command, slug, port, onUnexpectedStop, isMothership } =
|
||||
_cfg
|
||||
const _version = version || maxVersion // If _version is blank, we use the max version available
|
||||
const bin = (await getVersion(_version)).binPath
|
||||
if (!existsSync(bin)) {
|
||||
@ -157,6 +161,10 @@ export const createPocketbaseService = async (
|
||||
`${DAEMON_PB_DATA_DIR}/${slug}/pb_data`,
|
||||
`--publicDir`,
|
||||
`${DAEMON_PB_DATA_DIR}/${slug}/pb_static`,
|
||||
`--migrationsDir`,
|
||||
isMothership
|
||||
? DAEMON_PB_MIGRATIONS_DIR
|
||||
: `${DAEMON_PB_DATA_DIR}/${slug}/pb_migrations`,
|
||||
]
|
||||
if (command === 'serve') {
|
||||
args.push(`--http`)
|
||||
|
@ -1,12 +1,7 @@
|
||||
import { DAEMON_PB_DATA_DIR, PUBLIC_APP_DB } from '$constants'
|
||||
import { logger, safeCatch } from '@pockethost/common'
|
||||
import { Knex } from 'knex'
|
||||
import {
|
||||
Collection,
|
||||
default as PocketBase,
|
||||
default as pocketbaseEs,
|
||||
} from 'pocketbase'
|
||||
import { Collection_Serialized } from '../../migrate/schema'
|
||||
import { default as PocketBase, default as pocketbaseEs } from 'pocketbase'
|
||||
import { createBackupMixin } from './BackupMixin'
|
||||
import { createInstanceMixin } from './InstanceMIxin'
|
||||
import { createInvocationMixin } from './InvocationMixin'
|
||||
@ -45,13 +40,6 @@ export const createPbClient = (url: string) => {
|
||||
})
|
||||
)
|
||||
|
||||
const applySchema = safeCatch(
|
||||
`applySchema`,
|
||||
async (collections: Collection_Serialized[]) => {
|
||||
await client.collections.import(collections as Collection[], false)
|
||||
}
|
||||
)
|
||||
|
||||
const context: MixinContext = { client, rawDb }
|
||||
const rpcApi = createRpcHelper(context)
|
||||
const instanceApi = createInstanceMixin(context)
|
||||
@ -64,7 +52,6 @@ export const createPbClient = (url: string) => {
|
||||
knex: rawDb,
|
||||
createFirstAdmin,
|
||||
adminAuthViaEmail,
|
||||
applySchema,
|
||||
...rpcApi,
|
||||
...instanceApi,
|
||||
...invocationApi,
|
||||
|
@ -5,7 +5,6 @@ import {
|
||||
PUBLIC_APP_DOMAIN,
|
||||
PUBLIC_APP_PROTOCOL,
|
||||
} from '$constants'
|
||||
import { schema } from '$src/migrate/schema'
|
||||
import { logger, mkSingleton } from '@pockethost/common'
|
||||
import { createPbClient } from './PbClient'
|
||||
|
||||
@ -31,15 +30,6 @@ export const clientService = mkSingleton(async (url: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
dbg(`Applying schema`)
|
||||
await client.applySchema(schema)
|
||||
dbg(`Schema applied`)
|
||||
} catch (e) {
|
||||
error(`Failed to apply base migration schema`)
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
return {
|
||||
client,
|
||||
shutdown() {
|
||||
|
@ -10,8 +10,8 @@ import { basename, resolve } from 'path'
|
||||
import { chdir, cwd } from 'process'
|
||||
import { Database } from 'sqlite3'
|
||||
import tmp from 'tmp'
|
||||
import { pexec } from '../migrate/pexec'
|
||||
import { ensureDirExists } from './ensureDirExists'
|
||||
import { pexec } from './pexec'
|
||||
|
||||
export type BackupProgress = {
|
||||
current: number
|
||||
|
@ -128,6 +128,11 @@ By default, PocketHost will download and run the latest version of PocketBase. I
|
||||
|
||||
# Release History
|
||||
|
||||
**0.7.0**
|
||||
|
||||
- PocketHost will now always select and run the latest version of PocketBase for new instances and for the PocketHost central database. This was previously restricted until PocketBase matured more, but we think it is safe now.
|
||||
- Now using native PocketBase migrations to manage PocketHost central database migrations. Roadmap has been updated with task to allow end users to put their PocketBase instance in maintenance mode and run migrations.
|
||||
|
||||
**0.6.1**
|
||||
|
||||
- Fixed semver locking error
|
||||
|
@ -61,6 +61,9 @@ Ideas, in no particular order...
|
||||
|
||||
- Version upgrades/downgrades
|
||||
|
||||
- Allow instance to be placed into maintenance mode
|
||||
- Allow maintenance mode instance to run migrations (check automigrate first?)
|
||||
- Allow instance to be shut down and restarted
|
||||
- [Allow user to move to platform that requires migrations](https://github.com/benallfree/pockethost/issues/72)
|
||||
- [Allow user to move between platforms that don't require migrations](https://github.com/benallfree/pockethost/issues/60)
|
||||
- [Allow user to move between versions on a given pocketbase platform](https://github.com/benallfree/pockethost/issues/59)
|
||||
|
Loading…
x
Reference in New Issue
Block a user