mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-07-17 16:47:05 +00:00
* docs: refresh docs for 3.2.0 — correct stale content, document recent features The hand-maintained VitePress docs under doc/ had drifted behind a lot of recent work. They are authored prose (not generated from the OpenAPI spec), so they need manual upkeep. This pass corrects content that was actively wrong and documents features shipped since they were last touched. Corrections (was wrong / misleading): - cli.md: every command used `node bin/foo.js`, but the scripts are TypeScript run via pnpm — copy-paste failed. Rewrote to `pnpm run --filter bin <script>`, documented ~13 previously-undocumented operator tools, and split running-vs-stopped requirements. Registered the missing `compactStalePads` script in bin/package.json so the documented invocation actually works. - stats.md: described a pre-Prometheus world. Rewrote for the gated `/stats` (JSON) and `/stats/prometheus` endpoints, the live metric set, the opt-in `scalingDiveMetrics` instruments (#7756), and `measured-core`. - admin/updates.md: removed three false "SMTP not yet wired" claims (it is, via nodemailer + the `mail.*` block), documented the `node-engine-mismatch` preflight check and the rollback/preflight failure emails, and stripped obsolete "PR 1 / PR 2" staging language now that all tiers ship. - api/http_api.md: added the undocumented `anonymizeAuthor` (GDPR Art. 17) call, fixed copyPad/movePad version annotations (1.2.8 → 1.2.9), corrected getPadID's param name (readOnlyID → roID), and dropped a reference to a non-existent `getEtherpad` API call. - skins.md: colibris is the current default, not an "experimental" skin for a future 2.0. - localization.md: bare `window._('key')` is unbound and returns undefined; recommend `window.html10n.get(...)` / data-l10n-id instead. - README.md: bumped the v2.2.5 upgrade example to v3.2.0; fixed a docker.adoc link to docker.md. - docker.md: added MAIL_*, ENABLE_METRICS, GDPR_AUTHOR_ERASURE_ENABLED, PRIVACY_BANNER_*, PUBLIC_URL, AUTHENTICATION_METHOD, ENABLE_DARK_MODE, ENABLE_PAD_WIDE_SETTINGS; fixed the SOCKETIO_MAX_HTTP_BUFFER_SIZE default (50000 → 1000000). New documentation: - configuration.md (new): how settings + `${VAR:default}` substitution work, trustProxy, and — the previously-undocumented feature — running under a subpath/ingress via x-proxy-path / X-Forwarded-Prefix / X-Ingress-Path, with the sanitizer rules and Traefik/NGINX examples. Wired into the VitePress sidebar and the index hero. - hooks_server-side.md: ccRegisterBlockElements (the server-side companion plugin authors miss), exportConvert, exportHTMLSend, createServer, restartServer, and clientReady (marked deprecated). - hooks_client-side.md: aceDrop, acePaste, handleClientTimesliderMessage_<name>. VitePress build passes. The legacy .adoc set was intentionally left in place — it still feeds the per-version doc archives published to ether.github.com at release time (bin/release.ts), so it is not dead and is out of scope here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: address Qodo review — drop .js invocations from configuration.md and CLI help - configuration.md: the settings-override example referenced a nonexistent `node src/node/server.js`. Use the supported launcher instead (`bin/run.sh -s <file>`), and note the runtime is server.ts via tsx. - compactStalePads.ts / compactPad.ts / compactAllPads.ts: their header comments and runtime usage output still printed `node bin/*.js`, which points at files that don't exist. Switched to the documented `pnpm run --filter bin <script>` form so the --help text matches the docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
101 lines
3.8 KiB
TypeScript
101 lines
3.8 KiB
TypeScript
'use strict';
|
|
|
|
/*
|
|
* Compact a pad's revision history to reclaim database space.
|
|
*
|
|
* Usage:
|
|
* pnpm run --filter bin compactPad <padID> # collapse all history
|
|
* pnpm run --filter bin compactPad <padID> --keep N # keep only the last N revisions
|
|
*
|
|
* Wraps the existing Cleanup helper (src/node/utils/Cleanup.ts) via the
|
|
* compactPad HTTP API so admins can trigger it from the CLI without
|
|
* routing through the admin settings UI. Destructive — export the pad as
|
|
* `.etherpad` first for backup.
|
|
*
|
|
* Issue #6194: long-lived pads with heavy edit history accumulate hundreds
|
|
* of megabytes in the DB; this tool is the per-pad brick for reclaiming
|
|
* that space without rotating to a new pad ID.
|
|
*/
|
|
import path from 'node:path';
|
|
import fs from 'node:fs';
|
|
import process from 'node:process';
|
|
|
|
// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
|
|
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
|
|
process.on('unhandledRejection', (err) => { throw err; });
|
|
|
|
const settings = require('ep_etherpad-lite/tests/container/loadSettings').loadSettings();
|
|
|
|
const baseURL = `${settings.ssl ? 'https' : 'http'}://${settings.ip}:${settings.port}`;
|
|
|
|
const apiGet = async (p: string): Promise<any> => {
|
|
const r = await fetch(baseURL + p);
|
|
if (!r.ok) throw new Error(`HTTP ${r.status} ${r.statusText}`);
|
|
return r.json();
|
|
};
|
|
const apiPost = async (p: string): Promise<any> => {
|
|
const r = await fetch(baseURL + p, {method: 'POST'});
|
|
if (!r.ok) throw new Error(`HTTP ${r.status} ${r.statusText}`);
|
|
return r.json();
|
|
};
|
|
|
|
const usage = () => {
|
|
console.error('Usage:');
|
|
console.error(' pnpm run --filter bin compactPad <padID>');
|
|
console.error(' pnpm run --filter bin compactPad <padID> --keep <N>');
|
|
process.exit(2);
|
|
};
|
|
|
|
const args = process.argv.slice(2);
|
|
if (args.length < 1 || args.length > 3) usage();
|
|
const padId = args[0];
|
|
|
|
let keepRevisions: number | null = null;
|
|
if (args.length === 3) {
|
|
if (args[1] !== '--keep') usage();
|
|
keepRevisions = Number(args[2]);
|
|
if (!Number.isInteger(keepRevisions) || keepRevisions < 0) {
|
|
console.error(`--keep expects a non-negative integer; got ${args[2]}`);
|
|
process.exit(2);
|
|
}
|
|
}
|
|
|
|
// get the API Key
|
|
const filePath = path.join(__dirname, '../APIKEY.txt');
|
|
const apikey = fs.readFileSync(filePath, {encoding: 'utf-8'}).trim();
|
|
|
|
(async () => {
|
|
const apiInfo = await apiGet('/api/');
|
|
const apiVersion: string | undefined = apiInfo.currentVersion;
|
|
if (!apiVersion) throw new Error('No version set in API');
|
|
|
|
// Pre-flight: show current revision count so operators can eyeball impact.
|
|
const countUri = `/api/${apiVersion}/getRevisionsCount?apikey=${apikey}&padID=${padId}`;
|
|
const countRes = await apiGet(countUri);
|
|
if (countRes.code !== 0) {
|
|
console.error(`getRevisionsCount failed: ${JSON.stringify(countRes)}`);
|
|
process.exit(1);
|
|
}
|
|
const before: number = countRes.data.revisions;
|
|
const strategy = keepRevisions == null ? 'collapse all' : `keep last ${keepRevisions}`;
|
|
console.log(`Pad ${padId}: ${before + 1} revision(s). Strategy: ${strategy}.`);
|
|
|
|
const params = new URLSearchParams({apikey, padID: padId});
|
|
if (keepRevisions != null) params.set('keepRevisions', String(keepRevisions));
|
|
const result = await apiPost(`/api/${apiVersion}/compactPad?${params.toString()}`);
|
|
if (result.code !== 0) {
|
|
console.error(`compactPad failed: ${JSON.stringify(result)}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Post-flight: the pad is now compacted. Re-read the rev count so the
|
|
// operator sees concrete savings.
|
|
const afterRes = await apiGet(countUri);
|
|
const after: number | undefined = afterRes?.data?.revisions;
|
|
if (after != null) {
|
|
console.log(`Done. Pad ${padId}: ${after + 1} revision(s) remaining ` +
|
|
`(was ${before + 1}).`);
|
|
} else {
|
|
console.log('Done.');
|
|
}
|
|
})();
|