chore: gobot retrofit

This commit is contained in:
Ben Allfree 2024-05-28 05:40:23 -04:00
parent c504112f0c
commit e98a5fd4bb
31 changed files with 504 additions and 458 deletions

View File

@ -13,7 +13,6 @@ MOTHERSHIP_MIGRATIONS_DIR=/path/to/dist/mothership-app/migrations
MOTHERSHIP_HOOKS_DIR=/path/to/dist/mothership-app/pb_hooks
DAEMON_DATA_ROOT=/path/to/.pockethost/data
DAEMON_INITIAL_PORT_POOL_SIZE=20
PH_BIN_CACHE=/path/to/.pockethost/pbincache
PH_FTP_PORT=21
SSL_KEY=/path/to/pockethost.key
SSL_CERT=/path/to/pockethost.crt

4
.gitignore vendored
View File

@ -7,14 +7,10 @@
.idea
**/.env
**/.env.*
.pbincache
osx
pocketbase
.svelte-kit
live-data
dist
.pockethost
version-cache
// This is needed because Docker bind mounts will copy this file
src/mothership-app/pb_hooks/src/versions.js

View File

@ -9,9 +9,6 @@ build
_site
forks
// This is needed because Docker bind mounts will copy this file
src/mothership-app/pb_hooks/src/versions.js
src/mothership-app/migrations
src/mothership-app/pb_hooks/types/types.d.ts
src/instance-app/types/types.d.ts

View File

@ -17,6 +17,7 @@
"frontends",
"fullchain",
"getenv",
"gobot",
"goja",
"IPCIDR",
"jsonifiable",
@ -37,7 +38,6 @@
"opengraph",
"PASV",
"pbgo",
"pbincache",
"PBOUNCE",
"pexec",
"pocketbase",
@ -46,6 +46,7 @@
"privkey",
"rizzdown",
"Rpcs",
"semvers",
"superadmin",
"syslogd",
"tailable",

View File

@ -22,9 +22,9 @@ module.exports = {
script: 'pnpm prod:cli mothership serve',
},
{
name: `downloader`,
name: `updater`,
restart_delay: 60 * 60 * 1000, // 1 hour
script: 'pnpm prod:cli download',
script: 'pnpm prod:cli mothership update',
},
{
name: `health`,

View File

@ -69,6 +69,8 @@
"ftp-srv": "github:pockethost/ftp-srv#0fc708bae0d5d7a55ce948767f082d6fcfb2af59",
"get-port": "^6.1.2",
"glob": "^10.3.10",
"gobot": "1.0.0-alpha.39",
"gobot-pocketbase": "0.22.8-alpha.22",
"http-proxy": "^1.18.1",
"http-proxy-middleware": "^2.0.6",
"ip-cidr": "^3.1.0",
@ -78,7 +80,6 @@
"nanoid": "^5.0.2",
"node-fetch": "^3.3.2",
"node-os-utils": "^1.3.7",
"pbgo": "1.0.0-alpha.3",
"pocketbase": "^0.20.1",
"rimraf": "^5.0.5",
"semver": "^7.5.4",
@ -145,6 +146,5 @@
"tsx": "^3.14.0",
"type-fest": "^4.6.0",
"typescript": "^5.2.2"
},
"packageManager": "pnpm@9.1.2"
}
}

286
pnpm-lock.yaml generated
View File

@ -80,6 +80,12 @@ importers:
glob:
specifier: ^10.3.10
version: 10.3.10
gobot:
specifier: 1.0.0-alpha.39
version: 1.0.0-alpha.39
gobot-pocketbase:
specifier: 0.22.8-alpha.22
version: 0.22.8-alpha.22
http-proxy:
specifier: ^1.18.1
version: 1.18.1
@ -107,9 +113,6 @@ importers:
node-os-utils:
specifier: ^1.3.7
version: 1.3.7
pbgo:
specifier: 1.0.0-alpha.3
version: 1.0.0-alpha.3
pocketbase:
specifier: ^0.20.1
version: 0.20.1
@ -958,6 +961,9 @@ packages:
'@s-libs/micro-dash@16.1.0':
resolution: {integrity: sha512-GmmtRb/vNl1RxErvm/d+ITfjbo4og/CXyYdqs4vpeFrJla0uSEbXwf9aJUXYvgORQDgXV6h9tdgDY6T88FRU3Q==}
'@s-libs/micro-dash@17.1.0':
resolution: {integrity: sha512-vnrChv6KQG/kgRSNmxH0IqcGx4gYlvnmkfzuKotQNZZMBTnDZOzHYr487LPRq1Rr0ohRDuDsz6WssSolyoowQg==}
'@sindresorhus/is@4.6.0':
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
engines: {node: '>=10'}
@ -1483,6 +1489,10 @@ packages:
assert-never@1.2.1:
resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==}
astral-regex@2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
async@3.2.4:
resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
@ -1838,6 +1848,10 @@ packages:
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
engines: {node: '>=16'}
commander@12.1.0:
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
engines: {node: '>=18'}
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
@ -2021,6 +2035,14 @@ packages:
decode-named-character-reference@1.0.2:
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
decompress-bzip2@4.0.0:
resolution: {integrity: sha512-RwEcbZWaM7F5EiYfsAXUmZ/KLEVAPjYXfGbb5bztXZQ3d5PMpXYxa/1j04QL/gjotRdmzpHh++/cxz+rNZ4AZg==}
engines: {node: '>=4'}
decompress-gz@0.0.1:
resolution: {integrity: sha512-YMdCWdxHvPplsTbV1tvr2oFJOtAFNxqVMFnKWEmePBXl+LKG5z5bFrowzc12Jzd7O29nnzI/D1M95Asx0Qa1fg==}
engines: {node: '>=4'}
decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
@ -2037,6 +2059,10 @@ packages:
resolution: {integrity: sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==}
engines: {node: '>=4'}
decompress-unzip@4.0.1:
resolution: {integrity: sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==}
engines: {node: '>=4'}
decompress-unzip@https://codeload.github.com/pockethost/decompress-unzip/tar.gz/6ef397b9a2df11d39c7b26ce779e123833844751:
resolution: {tarball: https://codeload.github.com/pockethost/decompress-unzip/tar.gz/6ef397b9a2df11d39c7b26ce779e123833844751}
version: 4.0.1
@ -2400,6 +2426,9 @@ packages:
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
engines: {node: '>=8.6.0'}
fast-safe-stringify@2.1.1:
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
fastparse@1.1.2:
resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==}
@ -2429,10 +2458,18 @@ packages:
resolution: {integrity: sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
file-type@19.0.0:
resolution: {integrity: sha512-s7cxa7/leUWLiXO78DVVfBVse+milos9FitauDLG1pI7lNaJ2+5lzPnr2N24ym+84HVwJL6hVuGfgVE+ALvU8Q==}
engines: {node: '>=18'}
file-type@3.9.0:
resolution: {integrity: sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==}
engines: {node: '>=0.10.0'}
file-type@4.4.0:
resolution: {integrity: sha512-f2UbFQEk7LXgWpi5ntcO86OeA/cC80fuDDDaX/fZ2ZGel+AF7leRQqBBW1eJNiiQkrZlAoM6P+VYP5P6bOlDEQ==}
engines: {node: '>=4'}
file-type@5.2.0:
resolution: {integrity: sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==}
engines: {node: '>=4'}
@ -2479,6 +2516,10 @@ packages:
resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
find-up@7.0.0:
resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==}
engines: {node: '>=18'}
find-versions@5.1.0:
resolution: {integrity: sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==}
engines: {node: '>=12'}
@ -2614,6 +2655,10 @@ packages:
resolution: {integrity: sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
get-stream@2.3.1:
resolution: {integrity: sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==}
engines: {node: '>=0.10.0'}
get-stream@3.0.0:
resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==}
engines: {node: '>=4'}
@ -2650,6 +2695,7 @@ packages:
glob@6.0.4:
resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==}
deprecated: Glob versions prior to v9 are no longer supported
glob@7.1.6:
resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
@ -2683,6 +2729,14 @@ packages:
resolution: {integrity: sha512-mTCC51QFadK75MvAhrL5nPVIP291NjML1guo10Sa7Yj04tJU4V++Vgm780NIddg9etQD9D8FM67hFGqM8EE2HQ==}
engines: {node: '>= 0.2.5'}
gobot-pocketbase@0.22.8-alpha.22:
resolution: {integrity: sha512-beNLlDjonodEiNNcPIxAY4yYAzxcNC0i4KUrinYboR2KtAfbeMb0zijeswVKkZBnopDYQAWqasBEFhsFO7oiUg==}
hasBin: true
gobot@1.0.0-alpha.39:
resolution: {integrity: sha512-nCELk7KOya33f/9eas2Ha8oLyr9gwzFBVVE8l8IchXSjHenxAAZCddqO5LiiajniLJy5zMXVK2LWDiEHwYVKXg==}
hasBin: true
gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
@ -2830,9 +2884,6 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
immutable@4.3.4:
resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==}
@ -3038,6 +3089,10 @@ packages:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
is-stream@4.0.1:
resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
engines: {node: '>=18'}
is-typedarray@1.0.0:
resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
@ -3128,9 +3183,6 @@ packages:
jstransformer@1.0.0:
resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==}
jszip@3.10.1:
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
junk@1.0.3:
resolution: {integrity: sha512-3KF80UaaSSxo8jVnRYtMKNGFOoVPBdkkVPsw+Ad0y4oxKXPduS6G6iHkrf69yJVff/VAaYXkV42rtZ7daJxU3w==}
engines: {node: '>=0.10.0'}
@ -3181,9 +3233,6 @@ packages:
resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==}
engines: {node: '>=14.16'}
lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
liftoff@4.0.0:
resolution: {integrity: sha512-rMGwYF8q7g2XhG2ulBmmJgWv25qBsqRbDn5gH0+wnuyeFt7QBJlHJmtg5qEdn4pN6WVAUMgXnIxytMFRX9c1aA==}
engines: {node: '>=10.13.0'}
@ -3246,6 +3295,9 @@ packages:
lodash.throttle@4.1.1:
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
lodash.truncate@4.4.2:
resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@ -3291,6 +3343,11 @@ packages:
resolution: {integrity: sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==}
engines: {node: '>=12'}
lzma-native@8.0.6:
resolution: {integrity: sha512-09xfg67mkL2Lz20PrrDeNYZxzeW7ADtpYFbwSQh9U8+76RIzx5QsJBMy8qikv3hbUPfpy6hqwxt6FcGK81g9AA==}
engines: {node: '>=10.0.0'}
hasBin: true
magic-string@0.27.0:
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
engines: {node: '>=12'}
@ -3332,6 +3389,9 @@ packages:
resolution: {integrity: sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==}
hasBin: true
markdown-table@3.0.3:
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
marked@9.1.5:
resolution: {integrity: sha512-14QG3shv8Kg/xc0Yh6TNkMj90wXH9mmldi5941I2OevfJ/FQAFLEwtwU2/FfgSAOMlWHrEukWSGQf8MiVYNG2A==}
engines: {node: '>= 16'}
@ -3629,6 +3689,9 @@ packages:
resolution: {integrity: sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==}
engines: {node: '>=10'}
node-addon-api@3.2.1:
resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
node-addon-api@4.3.0:
resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==}
@ -3652,6 +3715,10 @@ packages:
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
node-gyp-build@4.8.1:
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
hasBin: true
node-gyp@8.4.1:
resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==}
engines: {node: '>= 10.12.0'}
@ -3853,9 +3920,6 @@ packages:
resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==}
engines: {node: '>=14.16'}
pako@1.0.11:
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
param-case@3.0.4:
resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
@ -3936,10 +4000,6 @@ packages:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
pbgo@1.0.0-alpha.3:
resolution: {integrity: sha512-rL4as8mm9i4rRldtJHPCaRqXBzQi/HmnkcmNf36SzVBgBvlrz9pxkkz1FQNZUpmz3qzaQxKoYwrWOEhRazWmuA==}
hasBin: true
peek-readable@5.0.0:
resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==}
engines: {node: '>=14.16'}
@ -3968,6 +4028,14 @@ packages:
resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==}
engines: {node: '>=4'}
pinkie-promise@2.0.1:
resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==}
engines: {node: '>=0.10.0'}
pinkie@2.0.4:
resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==}
engines: {node: '>=0.10.0'}
pirates@4.0.6:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
@ -4397,6 +4465,11 @@ packages:
engines: {node: '>=10'}
hasBin: true
semver@7.6.2:
resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
engines: {node: '>=10'}
hasBin: true
send@0.18.0:
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
engines: {node: '>= 0.8.0'}
@ -4418,9 +4491,6 @@ packages:
resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==}
engines: {node: '>= 0.4'}
setimmediate@1.0.5:
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
@ -4486,6 +4556,10 @@ packages:
resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==}
engines: {node: '>=12'}
slice-ansi@4.0.0:
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
engines: {node: '>=10'}
slugify@1.6.6:
resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==}
engines: {node: '>=8.0.0'}
@ -4735,6 +4809,10 @@ packages:
resolution: {integrity: sha512-FI6xGyKM9dRdNCrCWiEy1QhRZskDYkW+lUNAIXkFeht0/XCsSdZ7UsPANFLk0h8b+8Is6Ll8bllUNjME+XCANA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
table@6.8.2:
resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==}
engines: {node: '>=10.0.0'}
tail@2.2.6:
resolution: {integrity: sha512-IQ6G4wK/t8VBauYiGPLx+d3fA5XjSVagjWV5SIYzvEvglbQjwEcukeYI68JOPpdydjxhZ9sIgzRlSmwSpphHyw==}
engines: {node: '>= 6.0.0'}
@ -4803,6 +4881,10 @@ packages:
resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
engines: {node: '>=8.17.0'}
tmp@0.2.3:
resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==}
engines: {node: '>=14.14'}
to-buffer@1.1.1:
resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==}
@ -4920,6 +5002,10 @@ packages:
resolution: {integrity: sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==}
engines: {node: '>=14.0'}
unicorn-magic@0.1.0:
resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
engines: {node: '>=18'}
unique-filename@1.1.1:
resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==}
@ -5562,7 +5648,7 @@ snapshots:
'@npmcli/fs@1.1.1':
dependencies:
'@gar/promisify': 1.1.3
semver: 7.5.4
semver: 7.6.2
optional: true
'@npmcli/move-file@1.1.2':
@ -5595,6 +5681,11 @@ snapshots:
tslib: 2.6.2
utility-types: 3.10.0
'@s-libs/micro-dash@17.1.0':
dependencies:
tslib: 2.6.2
utility-types: 3.10.0
'@sindresorhus/is@4.6.0': {}
'@sindresorhus/is@5.6.0': {}
@ -6114,6 +6205,8 @@ snapshots:
assert-never@1.2.1: {}
astral-regex@2.0.0: {}
async@3.2.4: {}
asynckit@0.4.0: {}
@ -6169,7 +6262,7 @@ snapshots:
bin-version-check@5.1.0:
dependencies:
bin-version: 6.0.0
semver: 7.5.4
semver: 7.6.2
semver-truncate: 3.0.0
bin-version@6.0.0:
@ -6555,6 +6648,8 @@ snapshots:
commander@11.1.0: {}
commander@12.1.0: {}
commander@2.20.3: {}
commander@4.1.1: {}
@ -6748,6 +6843,15 @@ snapshots:
dependencies:
character-entities: 2.0.2
decompress-bzip2@4.0.0:
dependencies:
file-type: 4.4.0
seek-bzip: 1.0.6
decompress-gz@0.0.1:
dependencies:
file-type: 5.2.0
decompress-response@6.0.0:
dependencies:
mimic-response: 3.1.0
@ -6772,6 +6876,13 @@ snapshots:
file-type: 5.2.0
is-stream: 1.1.0
decompress-unzip@4.0.1:
dependencies:
file-type: 3.9.0
get-stream: 2.3.1
pify: 2.3.0
yauzl: 2.10.0
decompress-unzip@https://codeload.github.com/pockethost/decompress-unzip/tar.gz/6ef397b9a2df11d39c7b26ce779e123833844751:
dependencies:
file-type: 3.9.0
@ -7208,6 +7319,8 @@ snapshots:
merge2: 1.4.1
micromatch: 4.0.5
fast-safe-stringify@2.1.1: {}
fastparse@1.1.2: {}
fastq@1.15.0:
@ -7237,8 +7350,16 @@ snapshots:
strtok3: 7.0.0
token-types: 5.0.1
file-type@19.0.0:
dependencies:
readable-web-to-node-stream: 3.0.2
strtok3: 7.0.0
token-types: 5.0.1
file-type@3.9.0: {}
file-type@4.4.0: {}
file-type@5.2.0: {}
file-type@6.2.0: {}
@ -7293,6 +7414,12 @@ snapshots:
locate-path: 7.2.0
path-exists: 5.0.0
find-up@7.0.0:
dependencies:
locate-path: 7.2.0
path-exists: 5.0.0
unicorn-magic: 0.1.0
find-versions@5.1.0:
dependencies:
semver-regex: 4.0.5
@ -7430,6 +7557,11 @@ snapshots:
get-port@6.1.2: {}
get-stream@2.3.1:
dependencies:
object-assign: 4.1.1
pinkie-promise: 2.0.1
get-stream@3.0.0: {}
get-stream@5.2.0:
@ -7521,6 +7653,39 @@ snapshots:
glossy@0.1.7: {}
gobot-pocketbase@0.22.8-alpha.22:
dependencies:
gobot: 1.0.0-alpha.39
gobot@1.0.0-alpha.39:
dependencies:
'@s-libs/micro-dash': 17.1.0
bottleneck: 2.19.5
commander: 12.1.0
decompress: 4.2.1
decompress-bzip2: 4.0.0
decompress-gz: 0.0.1
decompress-tar: 4.1.1
decompress-tarbz2: 4.1.1
decompress-targz: 4.1.1
decompress-unzip: 4.0.1
env-paths: 3.0.0
fast-safe-stringify: 2.1.1
file-type: 19.0.0
find-up: 7.0.0
glob: 10.3.10
is-stream: 4.0.1
json-stringify-safe: 5.0.1
lzma-native: 8.0.6
markdown-table: 3.0.3
node-fetch: 3.3.2
rimraf: 5.0.5
semver: 7.6.2
table: 6.8.2
tar-stream: 1.6.2
tmp: 0.2.3
unbzip2-stream: 1.4.3
gopd@1.0.1:
dependencies:
get-intrinsic: 1.2.2
@ -7700,8 +7865,6 @@ snapshots:
dependencies:
queue: 6.0.2
immediate@3.0.6: {}
immutable@4.3.4: {}
import-fresh@3.3.0:
@ -7873,6 +8036,8 @@ snapshots:
is-stream@2.0.1: {}
is-stream@4.0.1: {}
is-typedarray@1.0.0: {}
is-unc-path@1.0.0:
@ -7944,13 +8109,6 @@ snapshots:
is-promise: 2.2.2
promise: 7.3.1
jszip@3.10.1:
dependencies:
lie: 3.3.0
pako: 1.0.11
readable-stream: 2.3.8
setimmediate: 1.0.5
junk@1.0.3: {}
keyv@4.5.4:
@ -7988,10 +8146,6 @@ snapshots:
dependencies:
package-json: 8.1.1
lie@3.3.0:
dependencies:
immediate: 3.0.6
liftoff@4.0.0:
dependencies:
extend: 3.0.2
@ -8050,6 +8204,8 @@ snapshots:
lodash.throttle@4.1.1: {}
lodash.truncate@4.4.2: {}
lodash@4.17.21: {}
log-symbols@4.1.0:
@ -8097,6 +8253,12 @@ snapshots:
luxon@3.4.3: {}
lzma-native@8.0.6:
dependencies:
node-addon-api: 3.2.1
node-gyp-build: 4.8.1
readable-stream: 3.6.2
magic-string@0.27.0:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
@ -8157,6 +8319,8 @@ snapshots:
mdurl: 1.0.1
uc.micro: 1.0.6
markdown-table@3.0.3: {}
marked@9.1.5: {}
maximatch@0.1.0:
@ -8496,7 +8660,9 @@ snapshots:
node-abi@3.51.0:
dependencies:
semver: 7.5.4
semver: 7.6.2
node-addon-api@3.2.1: {}
node-addon-api@4.3.0: {}
@ -8516,6 +8682,8 @@ snapshots:
fetch-blob: 3.2.0
formdata-polyfill: 4.0.10
node-gyp-build@4.8.1: {}
node-gyp@8.4.1:
dependencies:
env-paths: 2.2.1
@ -8773,9 +8941,7 @@ snapshots:
got: 12.6.1
registry-auth-token: 5.0.2
registry-url: 6.0.1
semver: 7.5.4
pako@1.0.11: {}
semver: 7.6.2
param-case@3.0.4:
dependencies:
@ -8844,12 +9010,6 @@ snapshots:
path-type@4.0.0: {}
pbgo@1.0.0-alpha.3:
dependencies:
env-paths: 3.0.0
jszip: 3.10.1
node-fetch: 3.3.2
peek-readable@5.0.0: {}
pend@1.2.0: {}
@ -8870,6 +9030,12 @@ snapshots:
pify@3.0.0: {}
pinkie-promise@2.0.1:
dependencies:
pinkie: 2.0.4
pinkie@2.0.4: {}
pirates@4.0.6: {}
please-upgrade-node@3.2.0:
@ -9337,13 +9503,13 @@ snapshots:
semver-diff@4.0.0:
dependencies:
semver: 7.5.4
semver: 7.6.2
semver-regex@4.0.5: {}
semver-truncate@3.0.0:
dependencies:
semver: 7.5.4
semver: 7.6.2
semver@6.3.1: {}
@ -9351,6 +9517,8 @@ snapshots:
dependencies:
lru-cache: 6.0.0
semver@7.6.2: {}
send@0.18.0:
dependencies:
debug: 2.6.9
@ -9395,8 +9563,6 @@ snapshots:
gopd: 1.0.1
has-property-descriptors: 1.0.1
setimmediate@1.0.5: {}
setprototypeof@1.2.0: {}
sharp@0.32.6:
@ -9462,6 +9628,12 @@ snapshots:
slash@4.0.0: {}
slice-ansi@4.0.0:
dependencies:
ansi-styles: 4.3.0
astral-regex: 2.0.0
is-fullwidth-code-point: 3.0.0
slugify@1.6.6: {}
smart-buffer@4.2.0:
@ -9729,6 +9901,14 @@ snapshots:
syslog-parse@2.0.0: {}
table@6.8.2:
dependencies:
ajv: 8.12.0
lodash.truncate: 4.4.2
slice-ansi: 4.0.0
string-width: 4.2.3
strip-ansi: 6.0.1
tail@2.2.6: {}
tailwindcss@3.3.5:
@ -9842,6 +10022,8 @@ snapshots:
dependencies:
rimraf: 3.0.2
tmp@0.2.3: {}
to-buffer@1.1.1: {}
to-fast-properties@2.0.0: {}
@ -9934,6 +10116,8 @@ snapshots:
dependencies:
'@fastify/busboy': 2.0.0
unicorn-magic@0.1.0: {}
unique-filename@1.1.1:
dependencies:
unique-slug: 2.0.2

View File

@ -1,13 +0,0 @@
import { PocketbaseReleaseDownloadService } from '$services'
import { LoggerService } from '$shared'
import { discordAlert } from '$util'
export const download = async () => {
const logger = LoggerService().create(`download.ts`)
const { dbg, error, info, warn } = logger
info(`Starting`)
const { check } = PocketbaseReleaseDownloadService({})
await check().catch(discordAlert)
}

View File

@ -1,15 +0,0 @@
import { Command } from 'commander'
import { download } from './download'
type Options = {
debug: boolean
}
export const DownloadCommand = () => {
const cmd = new Command(`download`)
.description(`Download PocketBase versions`)
.action(async () => {
await download()
})
return cmd
}

View File

@ -1,4 +1,3 @@
import { PocketbaseReleaseVersionService } from '$services'
import { Command } from 'commander'
import { daemon } from './daemon'
@ -10,7 +9,6 @@ export const ServeCommand = () => {
const cmd = new Command(`serve`)
.description(`Run an edge daemon server`)
.action(async (options: Options) => {
await PocketbaseReleaseVersionService({})
await daemon()
})
return cmd

View File

@ -1,28 +1,20 @@
import {
DATA_ROOT,
DEBUG,
IS_DEV,
LS_WEBHOOK_SECRET,
mkContainerHomePath,
MOTHERSHIP_APP_DIR,
MOTHERSHIP_DATA_ROOT,
MOTHERSHIP_HOOKS_DIR,
MOTHERSHIP_MIGRATIONS_DIR,
MOTHERSHIP_NAME,
MOTHERSHIP_PORT,
MOTHERSHIP_SEMVER,
PH_VERSIONS,
mkContainerHomePath,
} from '$constants'
import {
PocketbaseReleaseVersionService,
PocketbaseService,
PortService,
} from '$services'
import { PortService } from '$services'
import { LoggerService } from '$shared'
import { gracefulExit } from '$util'
import copyfiles from 'copyfiles'
import { run } from 'pbgo'
import { GobotOptions, gobot } from 'gobot'
import { rimraf } from 'rimraf'
import { freshenPocketbaseVersions } from '../freshenPocketbaseVersions'
export type MothershipConfig = { isolate: boolean }
@ -59,66 +51,41 @@ export async function mothership(cfg: MothershipConfig) {
/** Launch central database */
info(`Serving`)
if (isolate) {
await PocketbaseReleaseVersionService({})
const pbService = await PocketbaseService({})
const { url, exitCode } = await pbService.spawn({
version: MOTHERSHIP_SEMVER(),
subdomain: MOTHERSHIP_NAME(),
instanceId: MOTHERSHIP_NAME(),
port: MOTHERSHIP_PORT(),
dev: DEBUG(),
env: {
DATA_ROOT: mkContainerHomePath(`data`),
LS_WEBHOOK_SECRET: LS_WEBHOOK_SECRET(),
},
extraBinds: [
`${DATA_ROOT()}:${mkContainerHomePath(`data`)}`,
`${MOTHERSHIP_HOOKS_DIR()}:${mkContainerHomePath(`pb_hooks`)}`,
`${PH_VERSIONS()}:${mkContainerHomePath(`pb_hooks`, `versions.js`)}`,
`${MOTHERSHIP_MIGRATIONS_DIR()}:${mkContainerHomePath(
`pb_migrations`,
)}`,
`${MOTHERSHIP_APP_DIR()}:${mkContainerHomePath(`ph_app`)}`,
],
})
info(`Mothership URL for this session is ${url}`)
exitCode.then((c) => {
gracefulExit(c)
})
} else {
await rimraf(MOTHERSHIP_DATA_ROOT(`pb_hooks`))
await _copy(MOTHERSHIP_HOOKS_DIR(`**/*`), MOTHERSHIP_DATA_ROOT(`pb_hooks`))
await _copy(PH_VERSIONS(), MOTHERSHIP_DATA_ROOT(`pb_hooks`))
await rimraf(MOTHERSHIP_DATA_ROOT(`pb_migrations`))
await _copy(
MOTHERSHIP_MIGRATIONS_DIR(`**/*`),
MOTHERSHIP_DATA_ROOT(`pb_migrations`),
)
const args = [
`serve`,
`--http`,
`0.0.0.0:${MOTHERSHIP_PORT()}`,
`--dir`,
MOTHERSHIP_DATA_ROOT(`pb_data`),
`--hooksDir`,
MOTHERSHIP_DATA_ROOT(`pb_hooks`),
`--migrationsDir`,
MOTHERSHIP_DATA_ROOT(`pb_migrations`),
`--publicDir`,
MOTHERSHIP_DATA_ROOT(`pb_public`),
]
if (IS_DEV()) {
args.push(`--dev`)
}
dbg(args)
const process = run(args, {
env: {
DATA_ROOT: DATA_ROOT(),
LS_WEBHOOK_SECRET: LS_WEBHOOK_SECRET(),
},
version: MOTHERSHIP_SEMVER(),
debug: DEBUG(),
})
const env = {
DATA_ROOT: mkContainerHomePath(`data`),
LS_WEBHOOK_SECRET: LS_WEBHOOK_SECRET(),
}
dbg(env)
await rimraf(MOTHERSHIP_DATA_ROOT(`pb_hooks`))
await _copy(MOTHERSHIP_HOOKS_DIR(`**/*`), MOTHERSHIP_DATA_ROOT(`pb_hooks`))
await rimraf(MOTHERSHIP_DATA_ROOT(`pb_migrations`))
await _copy(
MOTHERSHIP_MIGRATIONS_DIR(`**/*`),
MOTHERSHIP_DATA_ROOT(`pb_migrations`),
)
await freshenPocketbaseVersions()
const args = [
`serve`,
`--http`,
`0.0.0.0:${MOTHERSHIP_PORT()}`,
`--dir`,
MOTHERSHIP_DATA_ROOT(`pb_data`),
`--hooksDir`,
MOTHERSHIP_DATA_ROOT(`pb_hooks`),
`--migrationsDir`,
MOTHERSHIP_DATA_ROOT(`pb_migrations`),
`--publicDir`,
MOTHERSHIP_DATA_ROOT(`pb_public`),
]
if (IS_DEV()) {
args.push(`--dev`)
}
const options: Partial<GobotOptions> = {
version: MOTHERSHIP_SEMVER(),
env,
}
dbg(`args`, args)
dbg(`options`, options)
const bot = await gobot(`pocketbase`, options)
bot.run(args, { env })
}

View File

@ -0,0 +1,14 @@
import { Command } from 'commander'
import { freshenPocketbaseVersions } from '../freshenPocketbaseVersions'
type Options = {}
export const UpdateCommand = () => {
const cmd = new Command(`update`)
.description(`Update known PocketBase versions`)
.action(async (options: Options) => {
const cjs = await freshenPocketbaseVersions()
console.log(cjs)
})
return cmd
}

View File

@ -1,3 +1,7 @@
import { MOTHERSHIP_DATA_ROOT } from '$constants'
import { writeFileSync } from 'fs'
import { gobot } from 'gobot'
function compareSemVer(a: string, b: string): number {
// Consider wildcards as higher than any version number, hence represented by a large number for comparison
let splitA = a
@ -18,7 +22,7 @@ function compareSemVer(a: string, b: string): number {
return 0
}
export function expandAndSortSemVers(semvers: string[]): string[] {
function expandAndSortSemVers(semvers: string[]): string[] {
let expandedVersions = new Set<string>() // Use a set to avoid duplicates
// Helper function to add wildcard versions
@ -44,3 +48,12 @@ export function expandAndSortSemVers(semvers: string[]): string[] {
// Convert the set to an array and sort it using the custom semver comparison function
return Array.from(expandedVersions).sort(compareSemVer)
}
export async function freshenPocketbaseVersions() {
const bot = await gobot(`pocketbase`)
const rawVersions = await bot.versions()
const versions = expandAndSortSemVers(rawVersions)
const cjs = `module.exports = ${JSON.stringify(versions, null, 2)}`
writeFileSync(MOTHERSHIP_DATA_ROOT(`pb_hooks`, `versions.cjs`), cjs)
return cjs
}

View File

@ -1,5 +1,6 @@
import { Command } from 'commander'
import { ServeCommand } from './ServeCommand'
import { UpdateCommand } from './UpdateCommand'
type Options = {
debug: boolean
@ -9,5 +10,6 @@ export const MothershipCommand = () => {
const cmd = new Command(`mothership`)
.description(`Mothership commands`)
.addCommand(ServeCommand())
.addCommand(UpdateCommand())
return cmd
}

View File

@ -4,7 +4,6 @@ import { DEBUG, DefaultSettingsService, SETTINGS } from '$constants'
import { LogLevelName, LoggerService } from '$shared'
import { program } from 'commander'
import EventSource from 'eventsource'
import { DownloadCommand } from './commands/DownloadCommand'
import { EdgeCommand } from './commands/EdgeCommand'
import { FirewallCommand } from './commands/FirewallCommand'
import { HealthCommand } from './commands/HealthCommand'
@ -33,7 +32,6 @@ export const main = async () => {
.addCommand(FirewallCommand())
.addCommand(SendMailCommand())
.addCommand(ServeCommand())
.addCommand(DownloadCommand())
await program.parseAsync()
}

View File

@ -44,13 +44,14 @@ export const _MOTHERSHIP_NAME =
export const _MOTHERSHIP_APP_ROOT = (...paths: string[]) =>
join(
process.env.PH_MOTHERSHIP_APP_ROOT ||
join(_PH_PROJECT_ROOT, 'mothership-app'),
join(_PH_PROJECT_ROOT, `src`, 'mothership-app'),
...paths,
)
export const _INSTANCE_APP_ROOT = (...paths: string[]) =>
join(
process.env.PH_INSTANCE_APP_ROOT || join(_PH_PROJECT_ROOT, 'instance-app'),
process.env.PH_INSTANCE_APP_ROOT ||
join(_PH_PROJECT_ROOT, `src`, 'instance-app'),
...paths,
)
@ -67,7 +68,6 @@ export const SETTINGS = {
UPGRADE_MODE: mkBoolean(false),
PH_HOME: mkPath(_PH_HOME),
PH_VERSIONS: mkPath(join(_PH_HOME, `versions.js`), { required: false }),
PH_PROJECT_ROOT: mkPath(_PH_PROJECT_ROOT),
DEBUG: mkBoolean(_IS_DEV),
@ -95,7 +95,7 @@ export const SETTINGS = {
MOTHERSHIP_APP_DIR: mkPath(_MOTHERSHIP_APP_ROOT(`ph_app`), {
required: false,
}),
MOTHERSHIP_SEMVER: mkString(''),
MOTHERSHIP_SEMVER: mkString('*'),
MOTHERSHIP_PORT: mkNumber(8091),
INITIAL_PORT_POOL_SIZE: mkNumber(20),
@ -103,7 +103,6 @@ export const SETTINGS = {
NODE_ENV: mkString(`production`),
IS_DEV: mkBoolean(_IS_DEV),
TRACE: mkBoolean(false),
PH_BIN_CACHE: mkPath(join(_PH_HOME, '.pbincache'), { create: true }),
PH_FTP_PORT: mkNumber(21),
SSL_KEY: mkPath(join(_SSL_HOME, `${TLS_PFX}.key`)),
@ -190,7 +189,6 @@ export const instanceLogger = () => ioc.service('instanceLogger')
export const UPGRADE_MODE = () => settings().UPGRADE_MODE
export const PH_HOME = () => settings().PH_HOME
export const PH_VERSIONS = () => settings().PH_VERSIONS
export const PH_PROJECT_ROOT = () => settings().PH_PROJECT_ROOT
export const DEBUG = () => settings().DEBUG
@ -229,7 +227,6 @@ export const DATA_ROOT = () => settings().DATA_ROOT
export const NODE_ENV = () => settings().NODE_ENV
export const IS_DEV = () => settings().IS_DEV
export const TRACE = () => settings().TRACE
export const PH_BIN_CACHE = () => settings().PH_BIN_CACHE
export const PH_FTP_PORT = () => settings().PH_FTP_PORT
export const SSL_KEY = () => settings().SSL_KEY

View File

@ -8,7 +8,9 @@ routerAdd(
'/api/instance',
(c) => {
const dao = $app.dao()
const { audit, mkLog } = /** @type {Lib} */ (require(`${__hooks}/lib.js`))
const { audit, mkLog, versions } = /** @type {Lib} */ (
require(`${__hooks}/lib.js`)
)
const log = mkLog(`POST:instance`)
@ -45,8 +47,6 @@ routerAdd(
)
}
const { versions } = require(`${__hooks}/versions.js`)
const collection = dao.findCollectionByNameOrId('instances')
const record = new Record(collection)
record.set('uid', authRecord.getId())

View File

@ -1,12 +1,13 @@
/** Migrate version numbers */
onAfterBootstrap((e) => {
const dao = $app.dao()
const { audit, mkLog } = /** @type {Lib} */ (require(`${__hooks}/lib.js`))
const { audit, mkLog, versions } = /** @type {Lib} */ (
require(`${__hooks}/lib.js`)
)
const log = mkLog(`bootstrap`)
const records = dao.findRecordsByFilter(`instances`, '1=1')
const { versions } = require(`${__hooks}/versions.js`)
const unrecognized = []
records.forEach((record) => {
const v = record.get('version').trim()

View File

@ -2,8 +2,9 @@
/** Validate instance version */
onModelBeforeCreate((e) => {
const { versions } = /** @type {Lib} */ (require(`${__hooks}/lib.js`))
const dao = e.dao || $app.dao()
const { versions } = require(`${__hooks}/versions.js`)
const version = e.model.get('version')
if (!versions.includes(version)) {

View File

@ -3,7 +3,7 @@
/** Validate instance version */
onModelBeforeUpdate((e) => {
const dao = e.dao || $app.dao()
const { versions } = require(`${__hooks}/versions.js`)
const { versions } = /** @type {Lib} */ (require(`${__hooks}/lib.js`))
const version = e.model.get('version')
if (!versions.includes(version)) {

View File

@ -162,10 +162,14 @@ function removeEmptyKeys(obj) {
return sanitized
}
/** @type {Lib['versions']} */
const versions = require(`${__hooks}/versions.cjs`)
module.exports = {
audit,
processNotification,
mkLog,
enqueueNotification,
removeEmptyKeys,
versions,
}

View File

@ -102,6 +102,8 @@ routerAdd(
'POST',
'/api/signup',
(c) => {
const { versions } = /** @type {Lib} */ (require(`${__hooks}/lib.js`))
const dao = $app.dao()
const parsed = (() => {
const rawBody = readerToString(c.request().body)
@ -192,7 +194,6 @@ routerAdd(
instance.set('status', 'idle')
instance.set('notifyMaintenanceMode', true)
instance.set('syncAdmin', true)
const { versions } = require(`${__hooks}/versions.js`)
instance.set('version', versions[0])
txDao.saveRecord(instance)
} catch (e) {

View File

@ -5,7 +5,7 @@ routerAdd(
'GET',
'/api/versions',
(c) => {
const { versions } = require(`${__hooks}/versions.js`)
const { versions } = /** @type {Lib} */ (require(`${__hooks}/lib.js`))
return c.json(200, { versions })
} /* optional middlewares */,

View File

@ -0,0 +1,159 @@
module.exports = [
"0.22.*",
"0.22.12",
"0.22.11",
"0.22.10",
"0.22.9",
"0.22.8",
"0.22.7",
"0.22.6",
"0.22.5",
"0.22.4",
"0.22.3",
"0.22.2",
"0.22.1",
"0.22.0",
"0.21.*",
"0.21.3",
"0.21.2",
"0.21.1",
"0.21.0",
"0.20.*",
"0.20.7",
"0.20.6",
"0.20.5",
"0.20.4",
"0.20.3",
"0.20.2",
"0.20.1",
"0.20.0",
"0.20.0-rc3",
"0.20.0-rc2",
"0.20.0-rc",
"0.19.*",
"0.19.4",
"0.19.3",
"0.19.2",
"0.19.1",
"0.19.0",
"0.18.*",
"0.18.10",
"0.18.9",
"0.18.8",
"0.18.7",
"0.18.6",
"0.18.5",
"0.18.4",
"0.18.3",
"0.18.2",
"0.18.1",
"0.18.0",
"0.17.*",
"0.17.7",
"0.17.6",
"0.17.5",
"0.17.4",
"0.17.3",
"0.17.2",
"0.17.1",
"0.17.0",
"0.16.*",
"0.16.10",
"0.16.9",
"0.16.8",
"0.16.7",
"0.16.6",
"0.16.5",
"0.16.4",
"0.16.3",
"0.16.2",
"0.16.1",
"0.16.0",
"0.15.*",
"0.15.3",
"0.15.2",
"0.15.1",
"0.15.0",
"0.14.*",
"0.14.5",
"0.14.4",
"0.14.3",
"0.14.2",
"0.14.1",
"0.14.0",
"0.13.*",
"0.13.4",
"0.13.3",
"0.13.2",
"0.13.1",
"0.13.0",
"0.12.*",
"0.12.3",
"0.12.2",
"0.12.1",
"0.12.0",
"0.11.*",
"0.11.4",
"0.11.3",
"0.11.2",
"0.11.1",
"0.11.0",
"0.10.*",
"0.10.4",
"0.10.3",
"0.10.2",
"0.10.1",
"0.10.0",
"0.9.*",
"0.9.2",
"0.9.1",
"0.9.0",
"0.8.*",
"0.8.0",
"0.8.0-rc4",
"0.8.0-rc3",
"0.8.0-rc2",
"0.8.0-rc1",
"0.7.*",
"0.7.10",
"0.7.9",
"0.7.8",
"0.7.7",
"0.7.6",
"0.7.5",
"0.7.4",
"0.7.3",
"0.7.2",
"0.7.1",
"0.7.0",
"0.6.*",
"0.6.0",
"0.5.*",
"0.5.2",
"0.5.1",
"0.5.0",
"0.4.*",
"0.4.2",
"0.4.1",
"0.4.0",
"0.3.*",
"0.3.4",
"0.3.3",
"0.3.2",
"0.3.1",
"0.3.0",
"0.2.*",
"0.2.8",
"0.2.7",
"0.2.6",
"0.2.5",
"0.2.4",
"0.2.3",
"0.2.2",
"0.2.1",
"0.2.0",
"0.1.*",
"0.1.2",
"0.1.1",
"0.1.0"
]

View File

@ -52,4 +52,5 @@ interface Lib {
},
) => void
removeEmptyKeys: <T>(obj: T) => T
versions: string[]
}

View File

@ -16,11 +16,11 @@ import { asyncExitHook, mkInternalUrl, SyslogLogger, tryFetch } from '$util'
import { map } from '@s-libs/micro-dash'
import Docker, { Container, ContainerCreateOptions } from 'dockerode'
import { existsSync } from 'fs'
import { gobot } from 'gobot'
import MemoryStream from 'memorystream'
import { gte } from 'semver'
import { EventEmitter } from 'stream'
import { AsyncReturnType } from 'type-fest'
import { PocketbaseReleaseVersionService } from '../PocketbaseReleaseVersionService'
export type Env = { [_: string]: string }
export type SpawnConfig = {
@ -54,9 +54,11 @@ export const createPocketbaseService = async (
const _serviceLogger = LoggerService().create('PocketbaseService')
const { dbg, error, warn, abort } = _serviceLogger
const { getLatestVersion, getVersion } =
await PocketbaseReleaseVersionService()
const maxVersion = getLatestVersion()
const bot = await gobot(`pocketbase`, { os: 'linux' })
const maxVersion = (await bot.versions())[0]
if (!maxVersion) {
throw new Error(`No max version found for PocketBase`)
}
const _spawn = async (cfg: SpawnConfig) => {
const cm = createCleanupManager()
@ -98,8 +100,11 @@ export const createPocketbaseService = async (
})
const _version = version || maxVersion // If _version is blank, we use the max version available
const realVersion = await getVersion(_version)
const binPath = realVersion.binPath
const realVersion = await bot.maxSatisfyingVersion(_version)
if (!realVersion) {
throw new Error(`No PocketBase version satisfying ${_version}`)
}
const binPath = await bot.getBinaryPath(realVersion)
if (!existsSync(binPath)) {
throw new Error(
`PocketBase binary (${binPath}) not found. Contact pockethost.io.`,
@ -138,7 +143,7 @@ export const createPocketbaseService = async (
Env: map(
{
...env,
DEV: dev && gte(realVersion.version, `0.20.1`),
DEV: dev && gte(realVersion, `0.20.1`),
PH_APEX_DOMAIN: APEX_DOMAIN(),
},
(v, k) => `${k}=${v}`,

View File

@ -1,128 +0,0 @@
import { PH_BIN_CACHE, PH_VERSIONS } from '$constants'
import { LoggerService, SingletonBaseConfig, mkSingleton } from '$shared'
import { downloadAndExtract, mergeConfig, smartFetch } from '$util'
import { keys } from '@s-libs/micro-dash'
import Bottleneck from 'bottleneck'
import { chmodSync, existsSync, writeFileSync } from 'fs'
import { join } from 'path'
import { rsort } from 'semver'
import { expandAndSortSemVers } from './expandAndSortSemVers'
type Release = {
url: string
tag_name: string
prerelease: string
assets: {
name: string
browser_download_url: string
}[]
}
type Releases = Release[]
export type PocketbaseReleaseDownloadServiceConfig = SingletonBaseConfig & {
onlyOne: boolean
binCachePath: string
versionsCachePath: string
}
export const PocketbaseReleaseDownloadService = mkSingleton(
(config: Partial<PocketbaseReleaseDownloadServiceConfig> = {}) => {
const { binCachePath, versionsCachePath, onlyOne } = mergeConfig(
{
binCachePath: PH_BIN_CACHE(),
versionsCachePath: PH_VERSIONS(),
onlyOne: false,
},
config,
)
const _serviceLogger = LoggerService().create(
'PocketbaseReleaseDownloadService',
)
const { dbg, info, error, warn, abort } = _serviceLogger
dbg(`Initializing`)
const osName = 'linux' // type().toLowerCase()
const cpuArchitecture = process.arch === 'x64' ? 'amd64' : process.arch
dbg({ osName, cpuArchitecture })
const binPaths: { [_: string]: string } = {}
let maxVersion = ''
const check = async () => {
info(`Fetching info for PocketBase releases...`)
let releases = await smartFetch<Releases>(
`https://api.github.com/repos/pocketbase/pocketbase/releases?per_page=100`,
join(binCachePath, `releases.json`),
)
// dbg({ releases })
type Defined<T> = Exclude<T, undefined>
type NoUndefinedProperties<T> = {
[K in keyof T]: Defined<T[K]>
}
const filteredReleases = releases
.filter((release) => !release.prerelease)
.map((release) => {
const { tag_name, assets } = release
const sanitizedTagName = tag_name.slice(1)
const path = join(binCachePath, tag_name)
const url = assets.find((v) => {
// dbg(v.name)
return v.name.includes(osName) && v.name.includes(cpuArchitecture)
})?.browser_download_url
return { url, sanitizedTagName, path }
})
.filter(
(release): release is NoUndefinedProperties<typeof release> =>
!!release.url,
)
if (filteredReleases.length === 0) return
const limiter = new Bottleneck({ maxConcurrent: 5 })
const promises = (
onlyOne ? [filteredReleases[0]!] : filteredReleases
).map((release) =>
limiter.schedule(async () => {
const { url, sanitizedTagName, path } = release
const binPath = join(path, `pocketbase`)
info(`Checking ${binPath}`)
if (existsSync(binPath)) {
chmodSync(binPath, 0o775)
} else {
info(`Downloading ${url}...`)
await downloadAndExtract(url, binPath, _serviceLogger)
}
binPaths[sanitizedTagName] = binPath
}),
)
await Promise.all(promises)
console.log(`***keys`, keys(binPaths))
const sortedSemVers = expandAndSortSemVers(keys(binPaths))
writeFileSync(
versionsCachePath,
`module.exports = ${JSON.stringify({ versions: sortedSemVers })}`,
)
info(`Saved to ${versionsCachePath}`, sortedSemVers)
if (keys(binPaths).length === 0) {
throw new Error(
`No version found, probably mismatched architecture and OS (${osName}/${cpuArchitecture})`,
)
}
maxVersion = `~${rsort(keys(binPaths))[0]}`
info(`Highest PocketBase version is ${maxVersion}`)
}
return {
check,
}
},
)

View File

@ -1,86 +0,0 @@
import { PH_BIN_CACHE } from '$constants'
import {
createTimerManager,
LoggerService,
mkSingleton,
SingletonBaseConfig,
} from '$shared'
import { mergeConfig } from '$util'
import { keys } from '@s-libs/micro-dash'
import { chmodSync, existsSync } from 'fs'
import { glob } from 'glob'
import { basename, join } from 'path'
import { maxSatisfying, rsort } from 'semver'
export type PocketbaseReleaseVersionService = SingletonBaseConfig & {
cachePath: string
checkIntervalMs: number
}
export const PocketbaseReleaseVersionService = mkSingleton(
async (config: Partial<PocketbaseReleaseVersionService> = {}) => {
const _serviceLogger = LoggerService().create(
'PocketbaseReleaseVersionService',
)
const { dbg, error, warn, abort } = _serviceLogger
dbg(`Initializing`)
const { cachePath, checkIntervalMs } = mergeConfig(
{
cachePath: PH_BIN_CACHE(),
checkIntervalMs: 1000 * 5 * 60,
},
config,
)
const binPaths: { [_: string]: string } = {}
let maxVersion = ''
const tm = createTimerManager()
const check = async () => {
const versions = await glob(join(cachePath, `v*/`))
versions.forEach((path) => {
const version = basename(path)
const sanitizedTagName = version.slice(1)
dbg(`Found a version ${sanitizedTagName}`)
const binPath = join(path, `pocketbase`)
dbg(`Checking ${binPath}`)
if (existsSync(binPath)) {
chmodSync(binPath, 0o775)
}
binPaths[sanitizedTagName] = binPath
})
maxVersion = `~${rsort(keys(binPaths))[0]}`
dbg({ maxVersion })
return true
}
await check().catch(error)
tm.repeat(check, checkIntervalMs, false)
const getLatestVersion = () => maxVersion
const getVersion = (semVer = maxVersion) => {
const version = maxSatisfying(keys(binPaths), semVer)
if (!version)
throw new Error(
`No version satisfies ${semVer} (${keys(binPaths).join(', ')})`,
)
const binPath = binPaths[version]
if (!binPath) throw new Error(`binPath for ${version} not found`)
return {
version,
binPath,
}
}
return {
getLatestVersion,
getVersion,
}
},
)

View File

@ -3,8 +3,6 @@ export * from './InstanceLoggerService'
export * from './InstanceService'
export * from './MothershipAdminClientService'
export * from './PocketBaseService'
export * from './PocketbaseReleaseDownloadService'
export * from './PocketbaseReleaseVersionService'
export * from './PortService'
export * from './ProxyService'
export * from './RealtimeLog'

View File

@ -1,47 +0,0 @@
import { Logger, singletonAsyncExecutionGuard } from '$shared'
import decompress from 'decompress'
import decompressUnzip from 'decompress-unzip'
import { chmodSync, createWriteStream } from 'fs'
import fetch from 'node-fetch'
import { dirname } from 'path'
import { assert } from './assert'
const downloadFile = async (url: string, path: string) => {
const { body } = await fetch(url)
assert(body, `Body is null`)
const fileStream = createWriteStream(path)
await new Promise<void>((resolve, reject) => {
body.pipe(fileStream)
body.on('error', reject)
fileStream.on('finish', resolve)
})
}
const _unsafe_downloadAndExtract = async (
url: string,
binPath: string,
logger: Logger,
) => {
const { dbg, info, error } = logger.create('downloadAndExtract')
dbg(`Fetching ${url}`)
const res = await fetch(url)
const { body } = res
if (!body) {
throw new Error(`Body expected for ${url}`)
}
const versionPath = dirname(binPath)
const zipPath = `${versionPath}.zip`
dbg(`Downloading ${url} to ${zipPath}`)
await downloadFile(url, zipPath)
// const tmpPath = tmpNameSync({ dir: TMP_DIR })
dbg(`Extracting ${zipPath} to ${versionPath}`)
await decompress(zipPath, versionPath, { plugins: [decompressUnzip()] })
// renameSync(tmpPath, versionPath)
chmodSync(binPath, 0o775)
}
export const downloadAndExtract = singletonAsyncExecutionGuard(
_unsafe_downloadAndExtract,
(url) => url,
)

View File

@ -3,7 +3,6 @@ export * from './Settings'
export * from './SyslogLogger'
export * from './assert'
export * from './discordAlert'
export * from './downloadAndExtract'
export * from './env'
export * from './exit'
export * from './internal'