create-meith 0.19.0 → 0.20.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 +50 -39
- package/package.json +1 -1
- package/src/bin.ts +1 -1
- package/src/index.ts +1 -1
- package/src/scaffold.ts +48 -37
package/dist/bin.mjs
CHANGED
|
@@ -25,7 +25,7 @@ var MATERIALIZED_AT_ROOT = [
|
|
|
25
25
|
];
|
|
26
26
|
var VERCEL_BUILD_COMMAND = `community migrate && forum-web build ${AT_ROOT_FLAG}`;
|
|
27
27
|
var TICK_PATH = "/api/system/tick";
|
|
28
|
-
var TICK_SCHEDULE = "
|
|
28
|
+
var TICK_SCHEDULE = "0 3 * * *";
|
|
29
29
|
var MATERIALIZED_PUBLIC = [
|
|
30
30
|
"placeholder-logo.png",
|
|
31
31
|
"placeholder-logo.svg",
|
|
@@ -330,7 +330,7 @@ var VERCEL_DERIVED_DRIVERS = [
|
|
|
330
330
|
"MAIL_DRIVER=http"
|
|
331
331
|
];
|
|
332
332
|
var VERCEL_PROMPTED_ENV = ["AUTH_SECRET", "CRON_SECRET"];
|
|
333
|
-
var
|
|
333
|
+
var VERCEL_MARKETPLACE_PRODUCTS = [
|
|
334
334
|
{ type: "integration", integrationSlug: "neon", productSlug: "neon", protocol: "storage" },
|
|
335
335
|
{
|
|
336
336
|
type: "integration",
|
|
@@ -338,7 +338,13 @@ var VERCEL_MARKETPLACE_STORES = [
|
|
|
338
338
|
productSlug: "upstash-kv",
|
|
339
339
|
protocol: "storage"
|
|
340
340
|
},
|
|
341
|
-
{ type: "blob" }
|
|
341
|
+
{ type: "blob" },
|
|
342
|
+
{
|
|
343
|
+
type: "integration",
|
|
344
|
+
integrationSlug: "resend",
|
|
345
|
+
productSlug: "resend-email",
|
|
346
|
+
protocol: "messaging"
|
|
347
|
+
}
|
|
342
348
|
];
|
|
343
349
|
function deployButtonUrl(templateRepositoryUrl) {
|
|
344
350
|
const params = new URLSearchParams([
|
|
@@ -348,10 +354,10 @@ function deployButtonUrl(templateRepositoryUrl) {
|
|
|
348
354
|
["env", VERCEL_PROMPTED_ENV.join(",")],
|
|
349
355
|
[
|
|
350
356
|
"envDescription",
|
|
351
|
-
"Two secrets, generated rather than chosen \u2014 32 characters or more each. Everything else the board reads from the database, cache
|
|
357
|
+
"Two secrets, generated rather than chosen \u2014 32 characters or more each. Everything else the board reads from the database, cache, blob store and mail provider this form links."
|
|
352
358
|
],
|
|
353
359
|
["envLink", `${templateRepositoryUrl}/blob/main/.env.example`],
|
|
354
|
-
["
|
|
360
|
+
["products", JSON.stringify(VERCEL_MARKETPLACE_PRODUCTS)],
|
|
355
361
|
["skippable-integrations", "1"]
|
|
356
362
|
]);
|
|
357
363
|
return `https://vercel.com/new/clone?${params.toString()}`;
|
|
@@ -1007,18 +1013,19 @@ A forum, built on [Meith](${repositoryUrl}), running as Vercel functions.
|
|
|
1007
1013
|
Vercel's SDK, which authenticates with the deployment's own OIDC identity, so
|
|
1008
1014
|
there is no token to copy. This is what used to be four hand-typed \`S3_*\`
|
|
1009
1015
|
secrets.
|
|
1016
|
+
- **A Resend mail account**, attached the same way, which publishes
|
|
1017
|
+
\`RESEND_API_KEY\`. The board reads that name directly: its mail driver already
|
|
1018
|
+
speaks Resend's request shape, so there is nothing to adapt.
|
|
1010
1019
|
- **A Vercel project** carrying \`vercel.json\` \u2014 the build command
|
|
1011
1020
|
\`${VERCEL_BUILD_COMMAND}\`,
|
|
1012
1021
|
which applies the schema before it builds, materializes the board's app at
|
|
1013
1022
|
the project root so the artefact lands where Vercel reads it, and the cron
|
|
1014
1023
|
entry that drives the tick.
|
|
1015
1024
|
|
|
1016
|
-
**Mail
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
board boots and runs without mail, and delivers nothing, silently, until it is
|
|
1021
|
-
done.
|
|
1025
|
+
**Mail needs one thing after the deploy**: the address the board sends from.
|
|
1026
|
+
It has to be at a domain Resend has verified, and no form can ask for that
|
|
1027
|
+
before the account exists \u2014 see *Mail, after the deploy* below. The board boots
|
|
1028
|
+
and runs without it, and delivers nothing, silently, until it is done.
|
|
1022
1029
|
|
|
1023
1030
|
## What to type into the deploy form
|
|
1024
1031
|
|
|
@@ -1069,26 +1076,22 @@ Vercel* below for why that matters \u2014 set \`FILESTORE_DRIVER=s3\` and add
|
|
|
1069
1076
|
project's environment settings, with \`S3_ENDPOINT\` for a bucket that is not AWS
|
|
1070
1077
|
(\`S3_REGION=auto\` for R2). The same board runs either way.
|
|
1071
1078
|
|
|
1072
|
-
## Mail,
|
|
1079
|
+
## Mail, after the deploy
|
|
1073
1080
|
|
|
1074
1081
|
A board that cannot send mail cannot reset a password, so do this before you
|
|
1075
|
-
invite anybody.
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
2.
|
|
1081
|
-
|
|
1082
|
-
3.
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
That is all. The integration publishes its key into the project as
|
|
1089
|
-
\`RESEND_API_KEY\`, and the board reads that name: with it set, and \`MAIL_FROM\`
|
|
1090
|
-
beside it, mail sends over Resend's HTTPS API with nothing further to
|
|
1091
|
-
configure.
|
|
1082
|
+
invite anybody. The deploy form already added Resend and published its key; two
|
|
1083
|
+
steps remain, and neither could have been answered on the form.
|
|
1084
|
+
|
|
1085
|
+
1. Verify your sending domain in the Resend dashboard if you have not already.
|
|
1086
|
+
Resend refuses to send from an address at a domain it has not verified.
|
|
1087
|
+
2. Add \`MAIL_FROM\` to the project's environment settings \u2014 an address at that
|
|
1088
|
+
verified domain, and the only mail value you ever type.
|
|
1089
|
+
3. Redeploy, or let the next push redeploy.
|
|
1090
|
+
|
|
1091
|
+
That is all. The integration published its key into the project as
|
|
1092
|
+
\`RESEND_API_KEY\` when you deployed, and the board reads that name: with it set,
|
|
1093
|
+
and \`MAIL_FROM\` beside it, mail sends over Resend's HTTPS API with nothing
|
|
1094
|
+
further to configure.
|
|
1092
1095
|
|
|
1093
1096
|
The board is not tied to Resend. Its mail driver is a plain JSON-over-HTTPS
|
|
1094
1097
|
sender that posts \`{from, to, subject, text, html, reply_to}\` with a bearer
|
|
@@ -1122,15 +1125,23 @@ drains; nothing here runs it on its own, because there is no worker process on
|
|
|
1122
1125
|
a function platform. Two things about it are worth knowing **before** you
|
|
1123
1126
|
deploy rather than after:
|
|
1124
1127
|
|
|
1125
|
-
- **
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1128
|
+
- **This ships a daily schedule, because Hobby refuses anything faster.** A
|
|
1129
|
+
Hobby plan rejects a cron expression that would run more than once a day \u2014
|
|
1130
|
+
the deployment fails outright rather than being slowed down \u2014 so
|
|
1131
|
+
\`vercel.json\` carries \`${TICK_SCHEDULE}\` and deploys anywhere. On a
|
|
1132
|
+
paid plan, edit it to \`* * * * *\` and the board ticks every minute.
|
|
1133
|
+
|
|
1134
|
+
A daily tick loses nothing permanently: tasks are written so a missed run
|
|
1135
|
+
delays work rather than dropping it, and a password reset is sent as the
|
|
1136
|
+
request is handled rather than waiting for a tick. What it does delay is
|
|
1137
|
+
everything the tick drives \u2014 a new post is not findable in search, and a
|
|
1138
|
+
notification is not sent, until the next run.
|
|
1139
|
+
|
|
1140
|
+
**To keep a fast tick without paying**, drive \`${TICK_PATH}\` from anything
|
|
1141
|
+
that can call a URL on a schedule \u2014 a GitHub Actions workflow, a systemd
|
|
1142
|
+
timer, an uptime pinger \u2014 presenting \`TICK_SECRET\` instead of
|
|
1143
|
+
\`CRON_SECRET\`. The endpoint accepts either, so the Vercel cron and an
|
|
1144
|
+
outside scheduler can both drive it.
|
|
1134
1145
|
- **\`maxDuration = 300\` is validated when the project builds, not when the
|
|
1135
1146
|
function runs.** A plan that does not allow 300 seconds therefore **fails the
|
|
1136
1147
|
deployment** rather than clamping the request. With Fluid Compute \u2014 the
|
|
@@ -1329,7 +1340,7 @@ async function run(argv, version) {
|
|
|
1329
1340
|
}
|
|
1330
1341
|
|
|
1331
1342
|
// src/bin.ts
|
|
1332
|
-
var result = await run(process.argv.slice(2), "0.
|
|
1343
|
+
var result = await run(process.argv.slice(2), "0.20.0");
|
|
1333
1344
|
for (const line of result.lines) {
|
|
1334
1345
|
if (result.code === 0) console.log(line);
|
|
1335
1346
|
else console.error(line);
|
package/package.json
CHANGED
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.20.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/index.ts
CHANGED
package/src/scaffold.ts
CHANGED
|
@@ -33,7 +33,7 @@ export const VERCEL_BUILD_COMMAND = `community migrate && forum-web build ${AT_R
|
|
|
33
33
|
|
|
34
34
|
export const TICK_PATH = '/api/system/tick'
|
|
35
35
|
|
|
36
|
-
export const TICK_SCHEDULE = '
|
|
36
|
+
export const TICK_SCHEDULE = '0 3 * * *'
|
|
37
37
|
|
|
38
38
|
export const MATERIALIZED_PUBLIC = [
|
|
39
39
|
'placeholder-logo.png',
|
|
@@ -359,7 +359,7 @@ const VERCEL_DERIVED_DRIVERS = [
|
|
|
359
359
|
|
|
360
360
|
export const VERCEL_PROMPTED_ENV = ['AUTH_SECRET', 'CRON_SECRET'] as const
|
|
361
361
|
|
|
362
|
-
export const
|
|
362
|
+
export const VERCEL_MARKETPLACE_PRODUCTS = [
|
|
363
363
|
{ type: 'integration', integrationSlug: 'neon', productSlug: 'neon', protocol: 'storage' },
|
|
364
364
|
{
|
|
365
365
|
type: 'integration',
|
|
@@ -368,6 +368,12 @@ export const VERCEL_MARKETPLACE_STORES = [
|
|
|
368
368
|
protocol: 'storage',
|
|
369
369
|
},
|
|
370
370
|
{ type: 'blob' },
|
|
371
|
+
{
|
|
372
|
+
type: 'integration',
|
|
373
|
+
integrationSlug: 'resend',
|
|
374
|
+
productSlug: 'resend-email',
|
|
375
|
+
protocol: 'messaging',
|
|
376
|
+
},
|
|
371
377
|
] as const
|
|
372
378
|
|
|
373
379
|
export function deployButtonUrl(templateRepositoryUrl: string): string {
|
|
@@ -378,10 +384,10 @@ export function deployButtonUrl(templateRepositoryUrl: string): string {
|
|
|
378
384
|
['env', VERCEL_PROMPTED_ENV.join(',')],
|
|
379
385
|
[
|
|
380
386
|
'envDescription',
|
|
381
|
-
'Two secrets, generated rather than chosen — 32 characters or more each. Everything else the board reads from the database, cache
|
|
387
|
+
'Two secrets, generated rather than chosen — 32 characters or more each. Everything else the board reads from the database, cache, blob store and mail provider this form links.',
|
|
382
388
|
],
|
|
383
389
|
['envLink', `${templateRepositoryUrl}/blob/main/.env.example`],
|
|
384
|
-
['
|
|
390
|
+
['products', JSON.stringify(VERCEL_MARKETPLACE_PRODUCTS)],
|
|
385
391
|
['skippable-integrations', '1'],
|
|
386
392
|
])
|
|
387
393
|
|
|
@@ -1068,18 +1074,19 @@ A forum, built on [Meith](${repositoryUrl}), running as Vercel functions.
|
|
|
1068
1074
|
Vercel's SDK, which authenticates with the deployment's own OIDC identity, so
|
|
1069
1075
|
there is no token to copy. This is what used to be four hand-typed \`S3_*\`
|
|
1070
1076
|
secrets.
|
|
1077
|
+
- **A Resend mail account**, attached the same way, which publishes
|
|
1078
|
+
\`RESEND_API_KEY\`. The board reads that name directly: its mail driver already
|
|
1079
|
+
speaks Resend's request shape, so there is nothing to adapt.
|
|
1071
1080
|
- **A Vercel project** carrying \`vercel.json\` — the build command
|
|
1072
1081
|
\`${VERCEL_BUILD_COMMAND}\`,
|
|
1073
1082
|
which applies the schema before it builds, materializes the board's app at
|
|
1074
1083
|
the project root so the artefact lands where Vercel reads it, and the cron
|
|
1075
1084
|
entry that drives the tick.
|
|
1076
1085
|
|
|
1077
|
-
**Mail
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
board boots and runs without mail, and delivers nothing, silently, until it is
|
|
1082
|
-
done.
|
|
1086
|
+
**Mail needs one thing after the deploy**: the address the board sends from.
|
|
1087
|
+
It has to be at a domain Resend has verified, and no form can ask for that
|
|
1088
|
+
before the account exists — see *Mail, after the deploy* below. The board boots
|
|
1089
|
+
and runs without it, and delivers nothing, silently, until it is done.
|
|
1083
1090
|
|
|
1084
1091
|
## What to type into the deploy form
|
|
1085
1092
|
|
|
@@ -1130,26 +1137,22 @@ Vercel* below for why that matters — set \`FILESTORE_DRIVER=s3\` and add
|
|
|
1130
1137
|
project's environment settings, with \`S3_ENDPOINT\` for a bucket that is not AWS
|
|
1131
1138
|
(\`S3_REGION=auto\` for R2). The same board runs either way.
|
|
1132
1139
|
|
|
1133
|
-
## Mail,
|
|
1140
|
+
## Mail, after the deploy
|
|
1134
1141
|
|
|
1135
1142
|
A board that cannot send mail cannot reset a password, so do this before you
|
|
1136
|
-
invite anybody.
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
2.
|
|
1142
|
-
|
|
1143
|
-
3.
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
That is all. The integration publishes its key into the project as
|
|
1150
|
-
\`RESEND_API_KEY\`, and the board reads that name: with it set, and \`MAIL_FROM\`
|
|
1151
|
-
beside it, mail sends over Resend's HTTPS API with nothing further to
|
|
1152
|
-
configure.
|
|
1143
|
+
invite anybody. The deploy form already added Resend and published its key; two
|
|
1144
|
+
steps remain, and neither could have been answered on the form.
|
|
1145
|
+
|
|
1146
|
+
1. Verify your sending domain in the Resend dashboard if you have not already.
|
|
1147
|
+
Resend refuses to send from an address at a domain it has not verified.
|
|
1148
|
+
2. Add \`MAIL_FROM\` to the project's environment settings — an address at that
|
|
1149
|
+
verified domain, and the only mail value you ever type.
|
|
1150
|
+
3. Redeploy, or let the next push redeploy.
|
|
1151
|
+
|
|
1152
|
+
That is all. The integration published its key into the project as
|
|
1153
|
+
\`RESEND_API_KEY\` when you deployed, and the board reads that name: with it set,
|
|
1154
|
+
and \`MAIL_FROM\` beside it, mail sends over Resend's HTTPS API with nothing
|
|
1155
|
+
further to configure.
|
|
1153
1156
|
|
|
1154
1157
|
The board is not tied to Resend. Its mail driver is a plain JSON-over-HTTPS
|
|
1155
1158
|
sender that posts \`{from, to, subject, text, html, reply_to}\` with a bearer
|
|
@@ -1183,15 +1186,23 @@ drains; nothing here runs it on its own, because there is no worker process on
|
|
|
1183
1186
|
a function platform. Two things about it are worth knowing **before** you
|
|
1184
1187
|
deploy rather than after:
|
|
1185
1188
|
|
|
1186
|
-
- **
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1189
|
+
- **This ships a daily schedule, because Hobby refuses anything faster.** A
|
|
1190
|
+
Hobby plan rejects a cron expression that would run more than once a day —
|
|
1191
|
+
the deployment fails outright rather than being slowed down — so
|
|
1192
|
+
\`vercel.json\` carries \`${TICK_SCHEDULE}\` and deploys anywhere. On a
|
|
1193
|
+
paid plan, edit it to \`* * * * *\` and the board ticks every minute.
|
|
1194
|
+
|
|
1195
|
+
A daily tick loses nothing permanently: tasks are written so a missed run
|
|
1196
|
+
delays work rather than dropping it, and a password reset is sent as the
|
|
1197
|
+
request is handled rather than waiting for a tick. What it does delay is
|
|
1198
|
+
everything the tick drives — a new post is not findable in search, and a
|
|
1199
|
+
notification is not sent, until the next run.
|
|
1200
|
+
|
|
1201
|
+
**To keep a fast tick without paying**, drive \`${TICK_PATH}\` from anything
|
|
1202
|
+
that can call a URL on a schedule — a GitHub Actions workflow, a systemd
|
|
1203
|
+
timer, an uptime pinger — presenting \`TICK_SECRET\` instead of
|
|
1204
|
+
\`CRON_SECRET\`. The endpoint accepts either, so the Vercel cron and an
|
|
1205
|
+
outside scheduler can both drive it.
|
|
1195
1206
|
- **\`maxDuration = 300\` is validated when the project builds, not when the
|
|
1196
1207
|
function runs.** A plan that does not allow 300 seconds therefore **fails the
|
|
1197
1208
|
deployment** rather than clamping the request. With Fluid Compute — the
|