diff --git a/README.md b/README.md
index eea5dfa..c4155fa 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,7 @@ rating encoding, and the bugs this rebuild fixes.
## Requirements
-- Node 20 or newer (uses `--experimental-strip-types`, so no build step for the API)
+- Node 22.18 or newer (native TypeScript type stripping, so no build step for the API)
- pnpm 9 or newer
## Setup
@@ -759,7 +759,7 @@ Wants=network-online.target
Type=simple
User=cashumints
WorkingDirectory=/srv/cashumints/api
-ExecStart=/usr/bin/node --experimental-strip-types src/index.ts
+ExecStart=/usr/bin/node src/index.ts
Environment=NODE_ENV=production
Environment=PORT=8787
Environment=DB_PATH=/var/lib/cashumints/cashumints.db
diff --git a/api/package.json b/api/package.json
index 908f6da..f61f2f4 100644
--- a/api/package.json
+++ b/api/package.json
@@ -4,16 +4,16 @@
"private": true,
"type": "module",
"scripts": {
- "dev": "node --env-file-if-exists=../.env --experimental-strip-types --watch src/index.ts",
- "start": "node --env-file-if-exists=../.env --experimental-strip-types src/index.ts",
- "seed": "node --env-file-if-exists=../.env --experimental-strip-types src/seed.ts",
- "migrate": "node --env-file-if-exists=../.env --experimental-strip-types src/migrate.ts",
+ "dev": "node --env-file-if-exists=../.env --watch src/index.ts",
+ "start": "node --env-file-if-exists=../.env src/index.ts",
+ "seed": "node --env-file-if-exists=../.env src/seed.ts",
+ "migrate": "node --env-file-if-exists=../.env src/migrate.ts",
"typecheck": "tsc -p tsconfig.json --noEmit",
- "test": "node --env-file-if-exists=../.env --experimental-strip-types src/check.ts",
- "test:warnings": "node --env-file-if-exists=../.env --experimental-strip-types src/check-warnings.ts",
- "test:offline": "node --env-file-if-exists=../.env --experimental-strip-types src/check-offline.ts",
- "test:lnurl": "node --env-file-if-exists=../.env --experimental-strip-types src/check-lnurl.ts",
- "test:index": "node --experimental-strip-types src/check-index.ts"
+ "test": "node --env-file-if-exists=../.env src/check.ts",
+ "test:warnings": "node --env-file-if-exists=../.env src/check-warnings.ts",
+ "test:offline": "node --env-file-if-exists=../.env src/check-offline.ts",
+ "test:lnurl": "node --env-file-if-exists=../.env src/check-lnurl.ts",
+ "test:index": "node src/check-index.ts"
},
"dependencies": {
"@cashumints/shared": "workspace:*",
diff --git a/package.json b/package.json
index aa61a39..45efc09 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"version": "2.0.0",
"type": "module",
"engines": {
- "node": ">=20"
+ "node": ">=22.18"
},
"scripts": {
"dev": "pnpm --parallel --filter ./api --filter ./web dev",
diff --git a/web/package.json b/web/package.json
index aa595ca..329ad06 100644
--- a/web/package.json
+++ b/web/package.json
@@ -13,7 +13,7 @@
"bones": "node --env-file-if-exists=../.env scripts/bones.mjs",
"check:links": "node scripts/check-links.mjs dist",
"check:i18n": "node scripts/check-i18n.mjs",
- "test": "node --experimental-strip-types --test test/*.test.mjs",
+ "test": "node --test test/*.test.mjs",
"check:hreflang": "node scripts/check-hreflang.mjs dist"
},
"dependencies": {
diff --git a/web/scripts/check-i18n.mjs b/web/scripts/check-i18n.mjs
index b6ec3f7..c4700ab 100644
--- a/web/scripts/check-i18n.mjs
+++ b/web/scripts/check-i18n.mjs
@@ -242,6 +242,8 @@ const DYNAMIC_PREFIXES = [
'fedimint.network.', // localNetworkName(network)
'feed.ecosystem.', // the /reviews filter, one option per ECOSYSTEMS entry
'reviews.dialog.bodyPlaceholder.', // one prompt per ecosystem, keyed by subject.type
+ 'reviews.dialog.lede.', // the dialog's invitation, one per ecosystem
+ 'reviews.rate.', // the reviews panel's inline "Rate this mint" row
];
const isDynamic = (key) => DYNAMIC_PREFIXES.some((prefix) => key.startsWith(prefix));
diff --git a/web/src/components/ReviewByUrl.astro b/web/src/components/ReviewByUrl.astro
index 6e28da2..c1e8020 100644
--- a/web/src/components/ReviewByUrl.astro
+++ b/web/src/components/ReviewByUrl.astro
@@ -37,16 +37,19 @@ const { locale } = pageLocale(Astro) as { locale: Locale };
const t = useI18n(locale);
/*
- * The label, the placeholder and the review prompt all differ per ecosystem, and all
- * three fall back to the Cashu wording for a type whose own string has not been written
- * — the same rule the reviews panel already applies to its placeholder.
+ * The label, the invitation and the two review prompts all differ per ecosystem, and
+ * all of them fall back to the Cashu wording for a type whose own string has not been
+ * written — the same rule the reviews panel already applies to its placeholder.
*/
-const wordsFor = (kind: IndexType): { label: string; placeholder: string; body: string } => {
+const wordsFor = (
+ kind: IndexType,
+): { label: string; placeholder: string; lede: string; body: string } => {
const key = (base: string): string =>
t.has(`${base}.${kind}`) ? `${base}.${kind}` : `${base}.cashu`;
return {
label: t(key('reviews.byUrl.label')),
placeholder: t(key('reviews.byUrl.placeholder')),
+ lede: t(key('reviews.dialog.lede')),
body: t(key('reviews.dialog.bodyPlaceholder')),
};
};
@@ -120,7 +123,7 @@ const initial = words[type] ?? words.cashu;
-
+
{t('reviews.byUrl.title')}
+ {/*
+ The way in, where the reviews are.
+
+ The header button at the top of the page is a long way from here, and by the time
+ somebody has read what other people wrote they are at the other end of the panel.
+ This is the same flow, opened the same way — one `[data-write-open]` among several
+ — with one addition: pressing a star opens the dialog with that star already
+ chosen, so a rating takes exactly one press.
+
+ One button rather than five, because five buttons cannot live inside one and a row
+ that is only reachable star by star is a row a keyboard cannot use. The stars are
+ spans; which one was pressed is read off the click.
+ */}
+
+
{/* One line of consequence when the toggle above is on: how much is showing. */}
@@ -206,7 +229,7 @@ function escapeText(value: string): string {
every page load.
-->