create-meith 0.26.1 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.mjs +72 -30
- package/package.json +1 -1
- package/src/bin.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/scaffold-extension.ts +1 -1
- package/src/scaffold.ts +69 -27
package/dist/bin.mjs
CHANGED
|
@@ -23,7 +23,7 @@ var MATERIALIZED_AT_ROOT = [
|
|
|
23
23
|
"tsconfig.json",
|
|
24
24
|
"next-env.d.ts"
|
|
25
25
|
];
|
|
26
|
-
var VERCEL_BUILD_COMMAND = `
|
|
26
|
+
var VERCEL_BUILD_COMMAND = `meith migrate && forum-web build ${AT_ROOT_FLAG}`;
|
|
27
27
|
var TICK_PATH = "/api/system/tick";
|
|
28
28
|
var TICK_SCHEDULE = "0 3 * * *";
|
|
29
29
|
var RESEND_SENDER_MAILBOX = "noreply";
|
|
@@ -85,7 +85,7 @@ var ENV_DATABASE_URL_PROSE = `# Your Postgres connection string.
|
|
|
85
85
|
# database rather than the cause. Your own Postgres, with a fixed number of
|
|
86
86
|
# processes in front of it, does not need one.`;
|
|
87
87
|
var ENV_DIRECT_DATABASE_URL_PROSE = `# The other half of that pair: the DIRECT (non-pooler) string, used only by
|
|
88
|
-
# \`
|
|
88
|
+
# \`meith migrate\` and \`meith backup\`. Migrations hold a session-level
|
|
89
89
|
# advisory lock so that two deploys landing together queue instead of both
|
|
90
90
|
# applying the same migration, and a transaction-mode pooler cannot hold that
|
|
91
91
|
# lock: it takes the connection back the moment the lock statement ends, which
|
|
@@ -213,7 +213,7 @@ DATABASE_URL=
|
|
|
213
213
|
${ENV_DIRECT_DATABASE_URL_PROSE}
|
|
214
214
|
#
|
|
215
215
|
# On Vercel this is not optional, and it is no longer yours to copy. DATABASE_URL
|
|
216
|
-
# here is the pooler string, the build runs \`
|
|
216
|
+
# here is the pooler string, the build runs \`meith migrate\` against it, and
|
|
217
217
|
# /install takes the second of those two session locks on first run. Left blank,
|
|
218
218
|
# the board reads Neon's own direct string \u2014 \`DATABASE_URL_UNPOOLED\` first, then
|
|
219
219
|
# \`POSTGRES_URL_NON_POOLING\` \u2014 and refuses to boot if neither is there, naming
|
|
@@ -250,7 +250,7 @@ CRON_SECRET=
|
|
|
250
250
|
#
|
|
251
251
|
# BLOB_READ_WRITE_TOKEN is the other way in, and you make it yourself on the
|
|
252
252
|
# store. Set it when something has to reach the store from OUTSIDE a Vercel
|
|
253
|
-
# deployment \u2014 \`
|
|
253
|
+
# deployment \u2014 \`meith backup\` run on your own machine is the case that
|
|
254
254
|
# matters \u2014 because there is no OIDC identity there to borrow. Set both and the
|
|
255
255
|
# board prefers the store id, unless the token names a different store, in which
|
|
256
256
|
# case the token wins: naming another store is a deliberate act.
|
|
@@ -401,7 +401,7 @@ function scaffold(options) {
|
|
|
401
401
|
dev: `forum-web dev${atRootFlag}`,
|
|
402
402
|
build: `forum-web build${atRootFlag}`,
|
|
403
403
|
start: `forum-web start${atRootFlag}`,
|
|
404
|
-
|
|
404
|
+
meith: "meith"
|
|
405
405
|
},
|
|
406
406
|
dependencies: {
|
|
407
407
|
"@meith/web": version,
|
|
@@ -489,7 +489,7 @@ export default defineForumConfig({
|
|
|
489
489
|
* ]
|
|
490
490
|
*
|
|
491
491
|
* and the matching entry in board.plugins.json, which is what
|
|
492
|
-
* \`
|
|
492
|
+
* \`meith plugin:add\`/\`plugin:remove\` read inside the monorepo \u2014 kept
|
|
493
493
|
* here too so the two files agree about what is installed.
|
|
494
494
|
*/
|
|
495
495
|
import type { InstalledPlugin } from '@meith/web/config'
|
|
@@ -552,8 +552,8 @@ updates:
|
|
|
552
552
|
# "Custom boards").
|
|
553
553
|
#
|
|
554
554
|
# Two stages, not three: unlike the official image, this does not prune down
|
|
555
|
-
# to Next's own standalone output. The migrate role below runs \`
|
|
556
|
-
# migrate\`, and \`
|
|
555
|
+
# to Next's own standalone output. The migrate role below runs \`meith
|
|
556
|
+
# migrate\`, and \`meith\` materializes @meith/cli's sources and runs them
|
|
557
557
|
# with tsx at the moment it runs (see the meith repository's
|
|
558
558
|
# docs/contributing/development.md, "Consuming the board from a workspace") \u2014 it needs
|
|
559
559
|
# the full, un-pruned node_modules tree this board installed, not what Next
|
|
@@ -628,8 +628,8 @@ ENTRYPOINT ["./docker-entrypoint.sh"]
|
|
|
628
628
|
# of minutes rather than a cold toolchain build.
|
|
629
629
|
#
|
|
630
630
|
# Two stages, not three: unlike the official image, this does not prune down
|
|
631
|
-
# to Next's own standalone output. The migrate role below runs \`
|
|
632
|
-
# migrate\`, and \`
|
|
631
|
+
# to Next's own standalone output. The migrate role below runs \`meith
|
|
632
|
+
# migrate\`, and \`meith\` materializes @meith/cli's sources and runs them
|
|
633
633
|
# with tsx at the moment it runs (see the meith repository's
|
|
634
634
|
# docs/contributing/development.md, "Consuming the board from a workspace") \u2014 it needs
|
|
635
635
|
# the full, un-pruned node_modules tree this board installed, not what Next
|
|
@@ -699,22 +699,22 @@ ENTRYPOINT ["./docker-entrypoint.sh"]
|
|
|
699
699
|
set -e
|
|
700
700
|
|
|
701
701
|
# An explicit command wins over the role, the same as the official image \u2014
|
|
702
|
-
# \`docker run <image> node_modules/.bin/
|
|
702
|
+
# \`docker run <image> node_modules/.bin/meith --help\` should still run
|
|
703
703
|
# the CLI rather than silently starting the web server.
|
|
704
704
|
if [ "$#" -gt 0 ]; then
|
|
705
705
|
exec "$@"
|
|
706
706
|
fi
|
|
707
707
|
|
|
708
|
-
case "\${
|
|
708
|
+
case "\${MEITH_ROLE:-web}" in
|
|
709
709
|
migrate)
|
|
710
710
|
# Runs to completion and exits; compose's one-shot service waits on it.
|
|
711
|
-
exec node_modules/.bin/
|
|
711
|
+
exec node_modules/.bin/meith migrate
|
|
712
712
|
;;
|
|
713
713
|
web)
|
|
714
714
|
exec node_modules/.bin/forum-web start
|
|
715
715
|
;;
|
|
716
716
|
*)
|
|
717
|
-
echo "Unknown
|
|
717
|
+
echo "Unknown MEITH_ROLE: \${MEITH_ROLE}. Expected 'web' or 'migrate'." >&2
|
|
718
718
|
exit 1
|
|
719
719
|
;;
|
|
720
720
|
esac
|
|
@@ -728,7 +728,7 @@ esac
|
|
|
728
728
|
# a health probe taken while it runs has no opinion.
|
|
729
729
|
set -e
|
|
730
730
|
|
|
731
|
-
if [ "\${
|
|
731
|
+
if [ "\${MEITH_ROLE:-web}" = "migrate" ]; then
|
|
732
732
|
exit 0
|
|
733
733
|
fi
|
|
734
734
|
|
|
@@ -865,7 +865,7 @@ services:
|
|
|
865
865
|
build: .
|
|
866
866
|
image: ${name}
|
|
867
867
|
environment:
|
|
868
|
-
|
|
868
|
+
MEITH_ROLE: migrate
|
|
869
869
|
DATABASE_URL: postgres://community:$SERVICE_PASSWORD_POSTGRES@postgres:5432/community
|
|
870
870
|
AUTH_SECRET: $SERVICE_BASE64_64_AUTH
|
|
871
871
|
TICK_SECRET: $SERVICE_BASE64_64_TICK
|
|
@@ -997,7 +997,7 @@ services:
|
|
|
997
997
|
# runs the old code.
|
|
998
998
|
pull_policy: always
|
|
999
999
|
environment:
|
|
1000
|
-
|
|
1000
|
+
MEITH_ROLE: migrate
|
|
1001
1001
|
DATABASE_URL: postgres://community:$SERVICE_PASSWORD_POSTGRES@postgres:5432/community
|
|
1002
1002
|
AUTH_SECRET: $SERVICE_BASE64_64_AUTH
|
|
1003
1003
|
TICK_SECRET: $SERVICE_BASE64_64_TICK
|
|
@@ -1196,7 +1196,7 @@ Two things nothing configures for you, on either path:
|
|
|
1196
1196
|
loop calling \`/api/system/tick\` once a minute, since \`@meith/web\`'s own
|
|
1197
1197
|
worker package is not something a board outside the meith monorepo can
|
|
1198
1198
|
depend on yet. Deploy some other way and something still has to call that
|
|
1199
|
-
route (or run \`
|
|
1199
|
+
route (or run \`meith task:run\`) every minute, or nothing catches up
|
|
1200
1200
|
and nothing errors.
|
|
1201
1201
|
|
|
1202
1202
|
## Local
|
|
@@ -1214,8 +1214,8 @@ Posting needs Postgres. Copy \`.env.example\` to \`.env.local\`, set
|
|
|
1214
1214
|
\`DATABASE_URL\` and the two secrets in it, then:
|
|
1215
1215
|
|
|
1216
1216
|
\`\`\`sh
|
|
1217
|
-
npm run
|
|
1218
|
-
echo "<password>" | npm run
|
|
1217
|
+
npm run meith -- migrate
|
|
1218
|
+
echo "<password>" | npm run meith -- user:create --username <name> --email <address> --group administrators
|
|
1219
1219
|
\`\`\`
|
|
1220
1220
|
|
|
1221
1221
|
## Configuring
|
|
@@ -1226,9 +1226,51 @@ echo "<password>" | npm run community -- user:create --username <name> --email <
|
|
|
1226
1226
|
- **\`/admin\`** \u2014 settings, forums, groups, members, themes, maintenance. An
|
|
1227
1227
|
administrator re-enters their password to get in, and again for anything
|
|
1228
1228
|
destructive.
|
|
1229
|
-
- **\`npm run
|
|
1229
|
+
- **\`npm run meith -- --help\`** \u2014 the operator CLI. Everything the panel does
|
|
1230
1230
|
and a few things it cannot, without a browser.
|
|
1231
1231
|
|
|
1232
|
+
## Installing plugins and themes
|
|
1233
|
+
|
|
1234
|
+
Nothing installs into a running container \u2014 a plugin or theme has to be
|
|
1235
|
+
built into the image, the same as any other dependency:
|
|
1236
|
+
|
|
1237
|
+
1. **In this repository**, install it:
|
|
1238
|
+
|
|
1239
|
+
\`\`\`sh
|
|
1240
|
+
npm install --save-exact @meith/plugin-dues
|
|
1241
|
+
\`\`\`
|
|
1242
|
+
|
|
1243
|
+
(a theme is the same command with its own package, e.g.
|
|
1244
|
+
\`@meith/theme-midnight\`).
|
|
1245
|
+
|
|
1246
|
+
2. **Register it.** A **theme** goes in \`meith.config.ts\`, in the \`themes\`
|
|
1247
|
+
map, following the shape of the \`default\` entry already there. A
|
|
1248
|
+
**plugin** goes in \`meith.plugins.ts\`: import its \`plugin\` and
|
|
1249
|
+
\`messages\` exports and add \`{ key, enabled: true, plugin, messages }\`
|
|
1250
|
+
to \`INSTALLED_PLUGINS\` \u2014 or run
|
|
1251
|
+
|
|
1252
|
+
\`\`\`sh
|
|
1253
|
+
npm run meith -- plugin:add @meith/plugin-dues
|
|
1254
|
+
\`\`\`
|
|
1255
|
+
|
|
1256
|
+
which edits \`board.plugins.json\` and regenerates \`meith.plugins.ts\`
|
|
1257
|
+
for you.
|
|
1258
|
+
|
|
1259
|
+
3. **Commit and push**, then **Redeploy** from Coolify \u2014 pushing alone does
|
|
1260
|
+
not rebuild. Quick start builds the new image on that redeploy; advanced/prebuilt
|
|
1261
|
+
waits for \`.github/workflows/build.yml\` to finish first, and Redeploy is
|
|
1262
|
+
what actually pulls the result.
|
|
1263
|
+
|
|
1264
|
+
4. **Once it is up, run its migrations one time:**
|
|
1265
|
+
|
|
1266
|
+
\`\`\`sh
|
|
1267
|
+
docker compose run --rm web meith upgrade
|
|
1268
|
+
\`\`\`
|
|
1269
|
+
|
|
1270
|
+
See [docs/customization/plugins.md](${repositoryUrl}/blob/main/docs/customization/plugins.md)
|
|
1271
|
+
and [docs/customization/themes.md](${repositoryUrl}/blob/main/docs/customization/themes.md)
|
|
1272
|
+
for the full reference.
|
|
1273
|
+
|
|
1232
1274
|
## Upgrading
|
|
1233
1275
|
|
|
1234
1276
|
\`\`\`sh
|
|
@@ -1269,7 +1311,7 @@ project's own \`.npmrc\` sets \`save-exact=true\` for the same reason, so an
|
|
|
1269
1311
|
\`npm install\` of anything else here \u2014 a plugin, say \u2014 stays pinned too; the
|
|
1270
1312
|
build workflow also refuses to build from anything but an exact version, as
|
|
1271
1313
|
a second line of defense. Once the rebuilt image is deployed, run
|
|
1272
|
-
\`npm run
|
|
1314
|
+
\`npm run meith -- upgrade\` against it for the plugin migrations \u2014 see
|
|
1273
1315
|
[the operator CLI](${repositoryUrl}/blob/main/docs/guides/operations/operating.md#the-operator-cli)
|
|
1274
1316
|
for running it against this deployment.
|
|
1275
1317
|
|
|
@@ -1512,9 +1554,9 @@ A board must stay movable, and the Blob store is the one part of this shape that
|
|
|
1512
1554
|
is not portable: Neon and Upstash hand out ordinary Postgres and Redis strings
|
|
1513
1555
|
that any host accepts, but a Vercel Blob store is reachable only through Vercel's
|
|
1514
1556
|
own API and there is no bucket to sync out of it. **The uploads are the thing you
|
|
1515
|
-
have to carry out deliberately, and \`
|
|
1557
|
+
have to carry out deliberately, and \`meith backup\` is how.**
|
|
1516
1558
|
|
|
1517
|
-
Under \`FILESTORE_DRIVER=blob\`, \`
|
|
1559
|
+
Under \`FILESTORE_DRIVER=blob\`, \`meith backup\` includes the uploads **by
|
|
1518
1560
|
default** \u2014 it walks the Blob store, pulls every object, and puts them in the
|
|
1519
1561
|
bundle beside the database dump. This is the opposite of the \`s3\` default, which
|
|
1520
1562
|
skips them, because a bucket has its own backup story you can drive yourself and
|
|
@@ -1525,7 +1567,7 @@ DATABASE_URL=\u2026 # Neon's pooled string
|
|
|
1525
1567
|
DIRECT_DATABASE_URL=\u2026 # Neon's DATABASE_URL_UNPOOLED
|
|
1526
1568
|
FILESTORE_DRIVER=blob
|
|
1527
1569
|
BLOB_READ_WRITE_TOKEN=\u2026 # create one on the store; see below
|
|
1528
|
-
npm run
|
|
1570
|
+
npm run meith -- backup
|
|
1529
1571
|
\`\`\`
|
|
1530
1572
|
|
|
1531
1573
|
Run that from a checkout of this repository, with those four values in the
|
|
@@ -1546,10 +1588,10 @@ so the same bundle moves the board either onward or away:
|
|
|
1546
1588
|
|
|
1547
1589
|
\`\`\`sh
|
|
1548
1590
|
# onto a self-hosted board with a bucket
|
|
1549
|
-
FILESTORE_DRIVER=s3 S3_BUCKET=\u2026 RESTORE_DATABASE_URL=\u2026 npm run
|
|
1591
|
+
FILESTORE_DRIVER=s3 S3_BUCKET=\u2026 RESTORE_DATABASE_URL=\u2026 npm run meith -- restore bundle.tar.gz
|
|
1550
1592
|
|
|
1551
1593
|
# onto a board that keeps uploads on its own disk
|
|
1552
|
-
RESTORE_DATABASE_URL=\u2026 npm run
|
|
1594
|
+
RESTORE_DATABASE_URL=\u2026 npm run meith -- restore bundle.tar.gz --uploads-dir ./uploads
|
|
1553
1595
|
\`\`\`
|
|
1554
1596
|
|
|
1555
1597
|
Take one before you need it. A Blob store deleted with the Vercel project takes
|
|
@@ -1893,7 +1935,7 @@ and add the matching entry to \`board.plugins.json\`:
|
|
|
1893
1935
|
{ "plugins": [{ "key": "${name}", "package": "${name}", "enabled": true }] }
|
|
1894
1936
|
|
|
1895
1937
|
Rebuild the board (\`npm run build\`) and, because this plugin ships a
|
|
1896
|
-
migration, run \`npx
|
|
1938
|
+
migration, run \`npx meith migrate\`. The plugin then appears under
|
|
1897
1939
|
**Admin \u2192 Plugins**.
|
|
1898
1940
|
|
|
1899
1941
|
## Publish and list it
|
|
@@ -2152,7 +2194,7 @@ async function run(argv, version) {
|
|
|
2152
2194
|
...kind === null ? [
|
|
2153
2195
|
"Then set DATABASE_URL, AUTH_SECRET and TICK_SECRET and deploy.",
|
|
2154
2196
|
"Something must run the tick every minute \u2014 the worker process, or",
|
|
2155
|
-
"`
|
|
2197
|
+
"`meith task:run`. Without it nothing catches up, and nothing errors."
|
|
2156
2198
|
] : [
|
|
2157
2199
|
`Then follow README.md \u2014 it walks through running the ${kind} inside a`,
|
|
2158
2200
|
"scaffolded board and submitting it to the meith.dev marketplace."
|
|
@@ -2162,7 +2204,7 @@ async function run(argv, version) {
|
|
|
2162
2204
|
}
|
|
2163
2205
|
|
|
2164
2206
|
// src/bin.ts
|
|
2165
|
-
var result = await run(process.argv.slice(2), "0.
|
|
2207
|
+
var result = await run(process.argv.slice(2), "0.27.0");
|
|
2166
2208
|
for (const line of result.lines) {
|
|
2167
2209
|
if (result.code === 0) console.log(line);
|
|
2168
2210
|
else console.error(line);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-meith",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Scaffold a Meith board, plugin or theme — npx create-meith <name> writes a deployable board workspace; --plugin and --theme write extension workspaces built on the published kits.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/src/bin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { run } from './cli'
|
|
3
3
|
|
|
4
|
-
const result = await run(process.argv.slice(2), '0.
|
|
4
|
+
const result = await run(process.argv.slice(2), '0.27.0')
|
|
5
5
|
for (const line of result.lines) {
|
|
6
6
|
if (result.code === 0) console.log(line)
|
|
7
7
|
else console.error(line)
|
package/src/cli.ts
CHANGED
|
@@ -145,7 +145,7 @@ export async function run(argv: readonly string[], version: string): Promise<Cli
|
|
|
145
145
|
? [
|
|
146
146
|
'Then set DATABASE_URL, AUTH_SECRET and TICK_SECRET and deploy.',
|
|
147
147
|
'Something must run the tick every minute — the worker process, or',
|
|
148
|
-
'`
|
|
148
|
+
'`meith task:run`. Without it nothing catches up, and nothing errors.',
|
|
149
149
|
]
|
|
150
150
|
: [
|
|
151
151
|
`Then follow README.md — it walks through running the ${kind} inside a`,
|
|
@@ -206,7 +206,7 @@ and add the matching entry to \`board.plugins.json\`:
|
|
|
206
206
|
{ "plugins": [{ "key": "${name}", "package": "${name}", "enabled": true }] }
|
|
207
207
|
|
|
208
208
|
Rebuild the board (\`npm run build\`) and, because this plugin ships a
|
|
209
|
-
migration, run \`npx
|
|
209
|
+
migration, run \`npx meith migrate\`. The plugin then appears under
|
|
210
210
|
**Admin → Plugins**.
|
|
211
211
|
|
|
212
212
|
## Publish and list it
|
package/src/scaffold.ts
CHANGED
|
@@ -29,7 +29,7 @@ export const MATERIALIZED_AT_ROOT = [
|
|
|
29
29
|
'next-env.d.ts',
|
|
30
30
|
]
|
|
31
31
|
|
|
32
|
-
export const VERCEL_BUILD_COMMAND = `
|
|
32
|
+
export const VERCEL_BUILD_COMMAND = `meith migrate && forum-web build ${AT_ROOT_FLAG}`
|
|
33
33
|
|
|
34
34
|
export const TICK_PATH = '/api/system/tick'
|
|
35
35
|
|
|
@@ -103,7 +103,7 @@ const ENV_DATABASE_URL_PROSE = `# Your Postgres connection string.
|
|
|
103
103
|
# processes in front of it, does not need one.`
|
|
104
104
|
|
|
105
105
|
const ENV_DIRECT_DATABASE_URL_PROSE = `# The other half of that pair: the DIRECT (non-pooler) string, used only by
|
|
106
|
-
# \`
|
|
106
|
+
# \`meith migrate\` and \`meith backup\`. Migrations hold a session-level
|
|
107
107
|
# advisory lock so that two deploys landing together queue instead of both
|
|
108
108
|
# applying the same migration, and a transaction-mode pooler cannot hold that
|
|
109
109
|
# lock: it takes the connection back the moment the lock statement ends, which
|
|
@@ -238,7 +238,7 @@ DATABASE_URL=
|
|
|
238
238
|
${ENV_DIRECT_DATABASE_URL_PROSE}
|
|
239
239
|
#
|
|
240
240
|
# On Vercel this is not optional, and it is no longer yours to copy. DATABASE_URL
|
|
241
|
-
# here is the pooler string, the build runs \`
|
|
241
|
+
# here is the pooler string, the build runs \`meith migrate\` against it, and
|
|
242
242
|
# /install takes the second of those two session locks on first run. Left blank,
|
|
243
243
|
# the board reads Neon's own direct string — \`DATABASE_URL_UNPOOLED\` first, then
|
|
244
244
|
# \`POSTGRES_URL_NON_POOLING\` — and refuses to boot if neither is there, naming
|
|
@@ -275,7 +275,7 @@ CRON_SECRET=
|
|
|
275
275
|
#
|
|
276
276
|
# BLOB_READ_WRITE_TOKEN is the other way in, and you make it yourself on the
|
|
277
277
|
# store. Set it when something has to reach the store from OUTSIDE a Vercel
|
|
278
|
-
# deployment — \`
|
|
278
|
+
# deployment — \`meith backup\` run on your own machine is the case that
|
|
279
279
|
# matters — because there is no OIDC identity there to borrow. Set both and the
|
|
280
280
|
# board prefers the store id, unless the token names a different store, in which
|
|
281
281
|
# case the token wins: naming another store is a deliberate act.
|
|
@@ -435,7 +435,7 @@ export function scaffold(options: ScaffoldOptions): ReadonlyMap<string, string>
|
|
|
435
435
|
dev: `forum-web dev${atRootFlag}`,
|
|
436
436
|
build: `forum-web build${atRootFlag}`,
|
|
437
437
|
start: `forum-web start${atRootFlag}`,
|
|
438
|
-
|
|
438
|
+
meith: 'meith',
|
|
439
439
|
},
|
|
440
440
|
dependencies: {
|
|
441
441
|
'@meith/web': version,
|
|
@@ -525,7 +525,7 @@ export default defineForumConfig({
|
|
|
525
525
|
* ]
|
|
526
526
|
*
|
|
527
527
|
* and the matching entry in board.plugins.json, which is what
|
|
528
|
-
* \`
|
|
528
|
+
* \`meith plugin:add\`/\`plugin:remove\` read inside the monorepo — kept
|
|
529
529
|
* here too so the two files agree about what is installed.
|
|
530
530
|
*/
|
|
531
531
|
import type { InstalledPlugin } from '@meith/web/config'
|
|
@@ -592,8 +592,8 @@ updates:
|
|
|
592
592
|
# "Custom boards").
|
|
593
593
|
#
|
|
594
594
|
# Two stages, not three: unlike the official image, this does not prune down
|
|
595
|
-
# to Next's own standalone output. The migrate role below runs \`
|
|
596
|
-
# migrate\`, and \`
|
|
595
|
+
# to Next's own standalone output. The migrate role below runs \`meith
|
|
596
|
+
# migrate\`, and \`meith\` materializes @meith/cli's sources and runs them
|
|
597
597
|
# with tsx at the moment it runs (see the meith repository's
|
|
598
598
|
# docs/contributing/development.md, "Consuming the board from a workspace") — it needs
|
|
599
599
|
# the full, un-pruned node_modules tree this board installed, not what Next
|
|
@@ -669,8 +669,8 @@ ENTRYPOINT ["./docker-entrypoint.sh"]
|
|
|
669
669
|
# of minutes rather than a cold toolchain build.
|
|
670
670
|
#
|
|
671
671
|
# Two stages, not three: unlike the official image, this does not prune down
|
|
672
|
-
# to Next's own standalone output. The migrate role below runs \`
|
|
673
|
-
# migrate\`, and \`
|
|
672
|
+
# to Next's own standalone output. The migrate role below runs \`meith
|
|
673
|
+
# migrate\`, and \`meith\` materializes @meith/cli's sources and runs them
|
|
674
674
|
# with tsx at the moment it runs (see the meith repository's
|
|
675
675
|
# docs/contributing/development.md, "Consuming the board from a workspace") — it needs
|
|
676
676
|
# the full, un-pruned node_modules tree this board installed, not what Next
|
|
@@ -741,22 +741,22 @@ ENTRYPOINT ["./docker-entrypoint.sh"]
|
|
|
741
741
|
set -e
|
|
742
742
|
|
|
743
743
|
# An explicit command wins over the role, the same as the official image —
|
|
744
|
-
# \`docker run <image> node_modules/.bin/
|
|
744
|
+
# \`docker run <image> node_modules/.bin/meith --help\` should still run
|
|
745
745
|
# the CLI rather than silently starting the web server.
|
|
746
746
|
if [ "$#" -gt 0 ]; then
|
|
747
747
|
exec "$@"
|
|
748
748
|
fi
|
|
749
749
|
|
|
750
|
-
case "\${
|
|
750
|
+
case "\${MEITH_ROLE:-web}" in
|
|
751
751
|
migrate)
|
|
752
752
|
# Runs to completion and exits; compose's one-shot service waits on it.
|
|
753
|
-
exec node_modules/.bin/
|
|
753
|
+
exec node_modules/.bin/meith migrate
|
|
754
754
|
;;
|
|
755
755
|
web)
|
|
756
756
|
exec node_modules/.bin/forum-web start
|
|
757
757
|
;;
|
|
758
758
|
*)
|
|
759
|
-
echo "Unknown
|
|
759
|
+
echo "Unknown MEITH_ROLE: \${MEITH_ROLE}. Expected 'web' or 'migrate'." >&2
|
|
760
760
|
exit 1
|
|
761
761
|
;;
|
|
762
762
|
esac
|
|
@@ -771,7 +771,7 @@ esac
|
|
|
771
771
|
# a health probe taken while it runs has no opinion.
|
|
772
772
|
set -e
|
|
773
773
|
|
|
774
|
-
if [ "\${
|
|
774
|
+
if [ "\${MEITH_ROLE:-web}" = "migrate" ]; then
|
|
775
775
|
exit 0
|
|
776
776
|
fi
|
|
777
777
|
|
|
@@ -911,7 +911,7 @@ services:
|
|
|
911
911
|
build: .
|
|
912
912
|
image: ${name}
|
|
913
913
|
environment:
|
|
914
|
-
|
|
914
|
+
MEITH_ROLE: migrate
|
|
915
915
|
DATABASE_URL: postgres://community:$SERVICE_PASSWORD_POSTGRES@postgres:5432/community
|
|
916
916
|
AUTH_SECRET: $SERVICE_BASE64_64_AUTH
|
|
917
917
|
TICK_SECRET: $SERVICE_BASE64_64_TICK
|
|
@@ -1044,7 +1044,7 @@ services:
|
|
|
1044
1044
|
# runs the old code.
|
|
1045
1045
|
pull_policy: always
|
|
1046
1046
|
environment:
|
|
1047
|
-
|
|
1047
|
+
MEITH_ROLE: migrate
|
|
1048
1048
|
DATABASE_URL: postgres://community:$SERVICE_PASSWORD_POSTGRES@postgres:5432/community
|
|
1049
1049
|
AUTH_SECRET: $SERVICE_BASE64_64_AUTH
|
|
1050
1050
|
TICK_SECRET: $SERVICE_BASE64_64_TICK
|
|
@@ -1244,7 +1244,7 @@ Two things nothing configures for you, on either path:
|
|
|
1244
1244
|
loop calling \`/api/system/tick\` once a minute, since \`@meith/web\`'s own
|
|
1245
1245
|
worker package is not something a board outside the meith monorepo can
|
|
1246
1246
|
depend on yet. Deploy some other way and something still has to call that
|
|
1247
|
-
route (or run \`
|
|
1247
|
+
route (or run \`meith task:run\`) every minute, or nothing catches up
|
|
1248
1248
|
and nothing errors.
|
|
1249
1249
|
|
|
1250
1250
|
## Local
|
|
@@ -1262,8 +1262,8 @@ Posting needs Postgres. Copy \`.env.example\` to \`.env.local\`, set
|
|
|
1262
1262
|
\`DATABASE_URL\` and the two secrets in it, then:
|
|
1263
1263
|
|
|
1264
1264
|
\`\`\`sh
|
|
1265
|
-
npm run
|
|
1266
|
-
echo "<password>" | npm run
|
|
1265
|
+
npm run meith -- migrate
|
|
1266
|
+
echo "<password>" | npm run meith -- user:create --username <name> --email <address> --group administrators
|
|
1267
1267
|
\`\`\`
|
|
1268
1268
|
|
|
1269
1269
|
## Configuring
|
|
@@ -1274,9 +1274,51 @@ echo "<password>" | npm run community -- user:create --username <name> --email <
|
|
|
1274
1274
|
- **\`/admin\`** — settings, forums, groups, members, themes, maintenance. An
|
|
1275
1275
|
administrator re-enters their password to get in, and again for anything
|
|
1276
1276
|
destructive.
|
|
1277
|
-
- **\`npm run
|
|
1277
|
+
- **\`npm run meith -- --help\`** — the operator CLI. Everything the panel does
|
|
1278
1278
|
and a few things it cannot, without a browser.
|
|
1279
1279
|
|
|
1280
|
+
## Installing plugins and themes
|
|
1281
|
+
|
|
1282
|
+
Nothing installs into a running container — a plugin or theme has to be
|
|
1283
|
+
built into the image, the same as any other dependency:
|
|
1284
|
+
|
|
1285
|
+
1. **In this repository**, install it:
|
|
1286
|
+
|
|
1287
|
+
\`\`\`sh
|
|
1288
|
+
npm install --save-exact @meith/plugin-dues
|
|
1289
|
+
\`\`\`
|
|
1290
|
+
|
|
1291
|
+
(a theme is the same command with its own package, e.g.
|
|
1292
|
+
\`@meith/theme-midnight\`).
|
|
1293
|
+
|
|
1294
|
+
2. **Register it.** A **theme** goes in \`meith.config.ts\`, in the \`themes\`
|
|
1295
|
+
map, following the shape of the \`default\` entry already there. A
|
|
1296
|
+
**plugin** goes in \`meith.plugins.ts\`: import its \`plugin\` and
|
|
1297
|
+
\`messages\` exports and add \`{ key, enabled: true, plugin, messages }\`
|
|
1298
|
+
to \`INSTALLED_PLUGINS\` — or run
|
|
1299
|
+
|
|
1300
|
+
\`\`\`sh
|
|
1301
|
+
npm run meith -- plugin:add @meith/plugin-dues
|
|
1302
|
+
\`\`\`
|
|
1303
|
+
|
|
1304
|
+
which edits \`board.plugins.json\` and regenerates \`meith.plugins.ts\`
|
|
1305
|
+
for you.
|
|
1306
|
+
|
|
1307
|
+
3. **Commit and push**, then **Redeploy** from Coolify — pushing alone does
|
|
1308
|
+
not rebuild. Quick start builds the new image on that redeploy; advanced/prebuilt
|
|
1309
|
+
waits for \`.github/workflows/build.yml\` to finish first, and Redeploy is
|
|
1310
|
+
what actually pulls the result.
|
|
1311
|
+
|
|
1312
|
+
4. **Once it is up, run its migrations one time:**
|
|
1313
|
+
|
|
1314
|
+
\`\`\`sh
|
|
1315
|
+
docker compose run --rm web meith upgrade
|
|
1316
|
+
\`\`\`
|
|
1317
|
+
|
|
1318
|
+
See [docs/customization/plugins.md](${repositoryUrl}/blob/main/docs/customization/plugins.md)
|
|
1319
|
+
and [docs/customization/themes.md](${repositoryUrl}/blob/main/docs/customization/themes.md)
|
|
1320
|
+
for the full reference.
|
|
1321
|
+
|
|
1280
1322
|
## Upgrading
|
|
1281
1323
|
|
|
1282
1324
|
\`\`\`sh
|
|
@@ -1317,7 +1359,7 @@ project's own \`.npmrc\` sets \`save-exact=true\` for the same reason, so an
|
|
|
1317
1359
|
\`npm install\` of anything else here — a plugin, say — stays pinned too; the
|
|
1318
1360
|
build workflow also refuses to build from anything but an exact version, as
|
|
1319
1361
|
a second line of defense. Once the rebuilt image is deployed, run
|
|
1320
|
-
\`npm run
|
|
1362
|
+
\`npm run meith -- upgrade\` against it for the plugin migrations — see
|
|
1321
1363
|
[the operator CLI](${repositoryUrl}/blob/main/docs/guides/operations/operating.md#the-operator-cli)
|
|
1322
1364
|
for running it against this deployment.
|
|
1323
1365
|
|
|
@@ -1577,9 +1619,9 @@ A board must stay movable, and the Blob store is the one part of this shape that
|
|
|
1577
1619
|
is not portable: Neon and Upstash hand out ordinary Postgres and Redis strings
|
|
1578
1620
|
that any host accepts, but a Vercel Blob store is reachable only through Vercel's
|
|
1579
1621
|
own API and there is no bucket to sync out of it. **The uploads are the thing you
|
|
1580
|
-
have to carry out deliberately, and \`
|
|
1622
|
+
have to carry out deliberately, and \`meith backup\` is how.**
|
|
1581
1623
|
|
|
1582
|
-
Under \`FILESTORE_DRIVER=blob\`, \`
|
|
1624
|
+
Under \`FILESTORE_DRIVER=blob\`, \`meith backup\` includes the uploads **by
|
|
1583
1625
|
default** — it walks the Blob store, pulls every object, and puts them in the
|
|
1584
1626
|
bundle beside the database dump. This is the opposite of the \`s3\` default, which
|
|
1585
1627
|
skips them, because a bucket has its own backup story you can drive yourself and
|
|
@@ -1590,7 +1632,7 @@ DATABASE_URL=… # Neon's pooled string
|
|
|
1590
1632
|
DIRECT_DATABASE_URL=… # Neon's DATABASE_URL_UNPOOLED
|
|
1591
1633
|
FILESTORE_DRIVER=blob
|
|
1592
1634
|
BLOB_READ_WRITE_TOKEN=… # create one on the store; see below
|
|
1593
|
-
npm run
|
|
1635
|
+
npm run meith -- backup
|
|
1594
1636
|
\`\`\`
|
|
1595
1637
|
|
|
1596
1638
|
Run that from a checkout of this repository, with those four values in the
|
|
@@ -1611,10 +1653,10 @@ so the same bundle moves the board either onward or away:
|
|
|
1611
1653
|
|
|
1612
1654
|
\`\`\`sh
|
|
1613
1655
|
# onto a self-hosted board with a bucket
|
|
1614
|
-
FILESTORE_DRIVER=s3 S3_BUCKET=… RESTORE_DATABASE_URL=… npm run
|
|
1656
|
+
FILESTORE_DRIVER=s3 S3_BUCKET=… RESTORE_DATABASE_URL=… npm run meith -- restore bundle.tar.gz
|
|
1615
1657
|
|
|
1616
1658
|
# onto a board that keeps uploads on its own disk
|
|
1617
|
-
RESTORE_DATABASE_URL=… npm run
|
|
1659
|
+
RESTORE_DATABASE_URL=… npm run meith -- restore bundle.tar.gz --uploads-dir ./uploads
|
|
1618
1660
|
\`\`\`
|
|
1619
1661
|
|
|
1620
1662
|
Take one before you need it. A Blob store deleted with the Vercel project takes
|