@materializecms/cli 0.1.0 → 0.2.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/CHANGELOG.md +8 -0
- package/compose.yaml +3 -2
- package/package.json +11 -6
- package/src/commands.js +61 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ Ogni versione, dalla più recente. Le novità in arrivo si scrivono sotto «Pros
|
|
|
4
4
|
|
|
5
5
|
## Prossima versione
|
|
6
6
|
|
|
7
|
+
## 0.2.0 — 2026-11-01
|
|
8
|
+
|
|
9
|
+
- **Password dimenticata?** nella pagina di accesso: un link per email, valido un'ora. Senza email configurata, il comando `materialize reset-password` stampa il link sul server, anche per l'unico amministratore.
|
|
10
|
+
- **Cronologia per le pagine sulla tela**: ogni versione si guarda su desktop, tablet e mobile prima di ripristinarla.
|
|
11
|
+
- **Esporta la pagina in PDF o PNG** dall'editor, per mandarla al cliente: desktop, tablet e mobile, ognuno come un'unica immagine lunga.
|
|
12
|
+
- **Guida per chi usa Materialize**, in `docs/guida`: installazione, editor, contenuti, lingue, SEO, persone, aggiornamenti, backup e problemi comuni.
|
|
13
|
+
- **Sicurezza**: i link degli inviti e delle nuove password puntano sempre all'indirizzo pubblico del sito, mai a quello dichiarato da chi fa la richiesta. Consigliato aggiornare.
|
|
14
|
+
|
|
7
15
|
## 0.1.0 — 2026-10-31
|
|
8
16
|
|
|
9
17
|
La prima versione pubblica.
|
package/compose.yaml
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Materialize with HTTPS, on a server where Docker is already there:
|
|
2
2
|
#
|
|
3
|
-
# DOMAIN=example.com docker compose
|
|
3
|
+
# echo "DOMAIN=example.com" > .env (read by every docker compose command in this folder)
|
|
4
|
+
# docker compose up -d
|
|
4
5
|
# docker compose logs materialize (the link to finish the installation in the browser)
|
|
5
6
|
#
|
|
6
7
|
# Caddy gets the Let's Encrypt certificate for the domain, which must already point to the server.
|
|
@@ -13,7 +14,7 @@ services:
|
|
|
13
14
|
volumes:
|
|
14
15
|
- site:/site
|
|
15
16
|
environment:
|
|
16
|
-
MATERIALIZE_SITE_URL: https://${DOMAIN:?Indica il dominio, per esempio DOMAIN=example.com
|
|
17
|
+
MATERIALIZE_SITE_URL: https://${DOMAIN:?Indica il dominio nel file .env, per esempio DOMAIN=example.com}
|
|
17
18
|
MATERIALIZE_TRUST_PROXY: "1"
|
|
18
19
|
# Other variables for the site go here, for example ANTHROPIC_API_KEY.
|
|
19
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@materializecms/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Il comando materialize: sviluppo, produzione con aggiornamenti dal pannello, generazione del sito, backup, MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"homepage": "https://github.com/materializecms/materialize#readme",
|
|
13
13
|
"bugs": "https://github.com/materializecms/materialize/issues",
|
|
14
14
|
"bin": {
|
|
15
|
-
"materialize": "
|
|
15
|
+
"materialize": "src/cli.js"
|
|
16
16
|
},
|
|
17
17
|
"exports": {
|
|
18
18
|
".": {
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@materializecms/astro": "0.
|
|
25
|
-
"@materializecms/core": "0.
|
|
26
|
-
"@materializecms/db": "0.
|
|
27
|
-
"@materializecms/server": "0.
|
|
24
|
+
"@materializecms/astro": "0.2.0",
|
|
25
|
+
"@materializecms/core": "0.2.0",
|
|
26
|
+
"@materializecms/db": "0.2.0",
|
|
27
|
+
"@materializecms/server": "0.2.0",
|
|
28
28
|
"@modelcontextprotocol/sdk": "1.32.2"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
44
|
"changelog": [
|
|
45
|
+
{
|
|
46
|
+
"version": "0.2.0",
|
|
47
|
+
"date": "2026-11-01",
|
|
48
|
+
"notes": "- **Password dimenticata?** nella pagina di accesso: un link per email, valido un'ora. Senza email configurata, il comando `materialize reset-password` stampa il link sul server, anche per l'unico amministratore.\n- **Cronologia per le pagine sulla tela**: ogni versione si guarda su desktop, tablet e mobile prima di ripristinarla.\n- **Esporta la pagina in PDF o PNG** dall'editor, per mandarla al cliente: desktop, tablet e mobile, ognuno come un'unica immagine lunga.\n- **Guida per chi usa Materialize**, in `docs/guida`: installazione, editor, contenuti, lingue, SEO, persone, aggiornamenti, backup e problemi comuni.\n- **Sicurezza**: i link degli inviti e delle nuove password puntano sempre all'indirizzo pubblico del sito, mai a quello dichiarato da chi fa la richiesta. Consigliato aggiornare."
|
|
49
|
+
},
|
|
45
50
|
{
|
|
46
51
|
"version": "0.1.0",
|
|
47
52
|
"date": "2026-10-31",
|
package/src/commands.js
CHANGED
|
@@ -4,7 +4,7 @@ import { copyFile, mkdir, open, readFile, rm, writeFile } from 'node:fs/promises
|
|
|
4
4
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
5
5
|
import { styleText } from 'node:util';
|
|
6
6
|
import { resolveRedirect } from '@materializecms/core/seo';
|
|
7
|
-
import { createAuthStore, createContentStore, createSettingsStore, openDatabase } from '@materializecms/db';
|
|
7
|
+
import { createActivityStore, createAuthStore, createContentStore, createSettingsStore, openDatabase, } from '@materializecms/db';
|
|
8
8
|
import { apiCaller, createFonts, createMcpServer, createMediaFiles, extractTarGz, restoreMedia, startServer, VERSION, } from '@materializecms/server';
|
|
9
9
|
import { findConfig, loadConfig } from './load-config.js';
|
|
10
10
|
import { buildSite, exportFonts, exportMedia, hasSite, ProductionSite, startDevSite } from './site.js';
|
|
@@ -25,6 +25,9 @@ ${accent('materialize')} ${dim(VERSION)}
|
|
|
25
25
|
materialize restore <file>
|
|
26
26
|
Rimette un backup (content-….db, o l'archivio completo materialize-….tar.gz);
|
|
27
27
|
il server va fermato
|
|
28
|
+
materialize reset-password <email>
|
|
29
|
+
Un link per una nuova password, valido un'ora: per chi non può riceverlo per email
|
|
30
|
+
(per esempio l'unico amministratore, senza email configurata)
|
|
28
31
|
materialize --help Mostra questo aiuto
|
|
29
32
|
|
|
30
33
|
Opzioni
|
|
@@ -345,6 +348,60 @@ async function restore(args) {
|
|
|
345
348
|
if (kept)
|
|
346
349
|
console.log(dim(` Il database di prima è in ${relative(process.cwd(), kept)}, se servisse tornare indietro.`));
|
|
347
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* A one-time link for a new password, printed here: the way back in for someone who cannot get it
|
|
353
|
+
* by email, such as the only administrator of a site without email. Only who can run commands on
|
|
354
|
+
* the server can ask for it. The server may be running.
|
|
355
|
+
*/
|
|
356
|
+
async function resetPassword(args) {
|
|
357
|
+
const email = args
|
|
358
|
+
.find((a) => !a.startsWith('--'))
|
|
359
|
+
?.trim()
|
|
360
|
+
.toLowerCase();
|
|
361
|
+
const path = findConfig(process.cwd());
|
|
362
|
+
if (!email || !path) {
|
|
363
|
+
console.error(fail(!email
|
|
364
|
+
? 'Indica l’email: materialize reset-password <email>'
|
|
365
|
+
: 'Non trovo materialize.config.ts in questa cartella: lancia il comando dalla cartella del sito.'));
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
const config = await loadConfig(path);
|
|
369
|
+
const database = await openDatabase(config.database);
|
|
370
|
+
try {
|
|
371
|
+
const auth = createAuthStore(database.db);
|
|
372
|
+
const user = await auth.findForLogin(email);
|
|
373
|
+
if (!user) {
|
|
374
|
+
console.error(fail(`Nessun account con l’email ${email}.`));
|
|
375
|
+
process.exitCode = 1;
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const { token } = await auth.createInvite({
|
|
379
|
+
kind: 'reset',
|
|
380
|
+
email: user.email,
|
|
381
|
+
name: user.name,
|
|
382
|
+
role: user.role,
|
|
383
|
+
userId: user.id,
|
|
384
|
+
ttlMs: 60 * 60 * 1000,
|
|
385
|
+
});
|
|
386
|
+
await createActivityStore(database.db).record({
|
|
387
|
+
userId: null,
|
|
388
|
+
userName: '',
|
|
389
|
+
action: 'password.reset_cli',
|
|
390
|
+
target: user.email,
|
|
391
|
+
detail: null,
|
|
392
|
+
ip: 'server',
|
|
393
|
+
});
|
|
394
|
+
const base = config.site.url?.replace(/\/+$/, '') ?? `http://localhost:${config.server.port}`;
|
|
395
|
+
console.log(` ${ok('✓')} Link per una nuova password di ${user.name} (${user.email}), valido un’ora:`);
|
|
396
|
+
console.log();
|
|
397
|
+
console.log(` ${accent(`${base}/admin/_invite/${token}`)}`);
|
|
398
|
+
console.log();
|
|
399
|
+
console.log(dim(' Chi lo apre sceglie la password. La verifica in due passaggi, se attiva, resta.'));
|
|
400
|
+
}
|
|
401
|
+
finally {
|
|
402
|
+
database.close();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
348
405
|
const [command = 'help', ...args] = process.argv.slice(2);
|
|
349
406
|
if (command === 'dev' || command === 'start' || command === 'build') {
|
|
350
407
|
await run(command, args);
|
|
@@ -352,6 +409,9 @@ if (command === 'dev' || command === 'start' || command === 'build') {
|
|
|
352
409
|
else if (command === 'mcp') {
|
|
353
410
|
await mcp(args);
|
|
354
411
|
}
|
|
412
|
+
else if (command === 'reset-password') {
|
|
413
|
+
await resetPassword(args);
|
|
414
|
+
}
|
|
355
415
|
else if (command === 'restore') {
|
|
356
416
|
await restore(args);
|
|
357
417
|
}
|