From 1cb243f128a8f79cac02ef9d99fd67ca95aa917b Mon Sep 17 00:00:00 2001 From: Etherpad Release Bot Date: Sun, 24 Aug 2025 20:36:27 +0000 Subject: [PATCH 1/5] bump version --- admin/package.json | 2 +- bin/package.json | 2 +- package.json | 2 +- src/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/admin/package.json b/admin/package.json index 06762f002..b659eb0fd 100644 --- a/admin/package.json +++ b/admin/package.json @@ -1,7 +1,7 @@ { "name": "admin", "private": true, - "version": "2.4.2", + "version": "2.5.0", "type": "module", "scripts": { "dev": "vite", diff --git a/bin/package.json b/bin/package.json index 7b2119a77..60abb63f8 100644 --- a/bin/package.json +++ b/bin/package.json @@ -1,6 +1,6 @@ { "name": "bin", - "version": "2.4.2", + "version": "2.5.0", "description": "", "main": "checkAllPads.js", "directories": { diff --git a/package.json b/package.json index 05938017d..bb3acfb0b 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,6 @@ "type": "git", "url": "https://github.com/ether/etherpad-lite.git" }, - "version": "2.4.2", + "version": "2.5.0", "license": "Apache-2.0" } diff --git a/src/package.json b/src/package.json index 916839eae..d8097591f 100644 --- a/src/package.json +++ b/src/package.json @@ -146,6 +146,6 @@ "debug:socketio": "cross-env DEBUG=socket.io* node --require tsx/cjs node/server.ts", "test:vitest": "vitest" }, - "version": "2.4.2", + "version": "2.5.0", "license": "Apache-2.0" } From 27e4f7290a1b0ed352269bd3919e56ec3263739b Mon Sep 17 00:00:00 2001 From: SamTV12345 <40429738+SamTV12345@users.noreply.github.com> Date: Sun, 24 Aug 2025 23:24:20 +0200 Subject: [PATCH 2/5] Potential fix for code scanning alert no. 107: Workflow does not contain permissions (#7091) Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52f58012f..caa3fd052 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,5 @@ +permissions: + contents: read name: Release etherpad on: workflow_dispatch: From 2f26cc0c86fb8c1835f31c01567f747f37f35265 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 25 Aug 2025 14:06:12 +0200 Subject: [PATCH 3/5] Localisation updates from https://translatewiki.net. --- src/locales/it.json | 1 + src/locales/kab.json | 14 +++++++++++--- src/locales/ps.json | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/locales/it.json b/src/locales/it.json index 7e0647494..b4cb5c8f3 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -30,6 +30,7 @@ "admin_plugins.page-title": "Gestore dei plugin - Etherpad", "admin_plugins.version": "Versione", "admin_plugins_info": "Informazioni sulla risoluzione dei problemi", + "admin_plugins_info.hooks": "Hook installati", "admin_plugins_info.hooks_client": "Hook lato client", "admin_plugins_info.hooks_server": "Hook lato server", "admin_plugins_info.parts": "Parti installate", diff --git a/src/locales/kab.json b/src/locales/kab.json index 77f7fa1ad..38f7ba99e 100644 --- a/src/locales/kab.json +++ b/src/locales/kab.json @@ -1,9 +1,16 @@ { "@metadata": { "authors": [ - "Belkacem77" + "Belkacem77", + "ButterflyOfFire" ] }, + "admin_plugins.name": "Isem", + "admin_plugins.version": "Lqem", + "admin_settings": "Iɣewwaren", + "admin_settings.current": "Tawila tamirant", + "admin_settings.current_save.value": "Sekles iɣewwaren", + "admin_settings.page-title": "Iɣewwaren - Etherpad", "index.newPad": "Apad amaynut", "index.createOpenPad": "neɣ rnu/ldi apad s yisem:", "pad.toolbar.bold.title": "Zur (Ctrl+B)", @@ -24,7 +31,7 @@ "pad.toolbar.embed.title": "Bḍu sakin seddu apad-agi", "pad.toolbar.showusers.title": "Sken iseqdacen ɣef upad-agi", "pad.colorpicker.save": "Sekles", - "pad.colorpicker.cancel": "Sefsex", + "pad.colorpicker.cancel": "Semmet", "pad.loading": "Asali...", "pad.noCookie": "Anagi n tuqqna ulac-it. Sireg inagan n tuqqna deg iminig-ik!", "pad.permissionDenied": "Ur ɣur-k ara tasiregt akken ad tkecmeḍ ar upad-agi", @@ -37,6 +44,7 @@ "pad.settings.rtlcheck": "Ɣeṛ agbur seg uyeffus s azelmaḍ?", "pad.settings.fontType": "Anaw n tsefsit:", "pad.settings.language": "Tutlayt:", + "pad.settings.about": "Ɣef", "pad.importExport.import_export": "Kter/Sifeḍ", "pad.importExport.import": "Sali aḍris neɣ isemli", "pad.importExport.importSuccessful": "Yedda!", @@ -52,7 +60,7 @@ "pad.modals.reconnecting": "Tulsa n tuqqna ar upad-ik.", "pad.modals.forcereconnect": "Ḥettem tulsa n tuqqna", "pad.modals.reconnecttimer": "Ɛreḍ tikelt-nniḍen tuqqna", - "pad.modals.cancel": "Sefsex", + "pad.modals.cancel": "Semmet", "pad.modals.userdup": "Yeldi deg usfaylu-nniḍen", "pad.modals.userdup.explanation": "Apad-agi yettban yeldi deg isfuyla-nniḍen deg uselkim-agi.", "pad.modals.userdup.advice": "Ales tuqqna akken ad tesqedceḍ asfaylu-agi.", diff --git a/src/locales/ps.json b/src/locales/ps.json index bad3d5f66..65544cebd 100644 --- a/src/locales/ps.json +++ b/src/locales/ps.json @@ -5,8 +5,26 @@ "شاه زمان پټان" ] }, + "admin_plugins.last-update": "وروستۍ هم‌مهالېدنه", + "admin_plugins.name": "نوم", + "admin_plugins.version": "بل‌بڼه", + "admin_plugins_info": "ستونزو اواري مالومات", + "admin_plugins_info.hooks": "ځای‌پرځای‌شوي چنگکونه", + "admin_plugins_info.version_latest": "وروستۍ د لاسرسي وړ بل‌بڼه", + "admin_plugins_info.version_number": "بل‌بڼې شمېره", + "admin_settings": "اوڼنې", + "admin_settings.current": "اوسنی ترتيب", + "admin_settings.current_example-devel": "د پراختيااوڼنې کينډۍ بېلگه", + "admin_settings.current_example-prod": "د توليد اوڼنې کينډۍ بېلگه", + "admin_settings.current_save.value": "اوڼنې خوندي‌کول", "index.newPad": "نوې ليکچه", "index.createOpenPad": "ليکچه د نوم له مخې پرانېستل", + "index.recentPads": "وروستۍ ليکچې", + "index.recentPadsEmpty": "هېڅ وروستۍ ليکچې ونه موندل شوې.", + "index.generateNewPad": "ناڅاپي ليکچې نوم پنځول", + "index.labelPad": "ليکچې نوم (اختياري)", + "index.placeholderPadEnter": "مهرباني وکړئ ليکچې نوم وليکئ...", + "index.createAndShareDocuments": "په رښتينې وخت کې لاسوندونه جوړ او شريک کړئ", "pad.toolbar.bold.title": "زغرد (Ctrl-B)", "pad.toolbar.italic.title": "رېوند (Ctrl-I)", "pad.toolbar.underline.title": "لرکرښن (Ctrl+U)", From 90517c12c513fe671b3e835dc31a979fa461512a Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Mon, 25 Aug 2025 19:50:31 +0200 Subject: [PATCH 4/5] fix "pnpm run plugins install ep_xxx" (#7093) With previous code, "pnpm run plugins i ep_xxx" is working correctly, but "pnpm run plugins install ep_xxx" does not work correctly (since var `registryPlugins` is empty) Either "pnpm run plugins install ep_xxx" should be disallowed (by removing `case "install"`) or this fix should be applied. --- bin/plugins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/plugins.ts b/bin/plugins.ts index 17c756f60..9b0b49633 100644 --- a/bin/plugins.ts +++ b/bin/plugins.ts @@ -24,7 +24,7 @@ const possibleActions = [ const install = ()=> { const argsAsString: string = args.join(" "); - const regexRegistryPlugins = /(?<=i\s)(.*?)(?=--github|--path|$)/; + const regexRegistryPlugins = /(?<=(?:i|install)\s)(.*?)(?=--github|--path|$)/; const regexLocalPlugins = /(?<=--path\s)(.*?)(?=--github|$)/; const regexGithubPlugins = /(?<=--github\s)(.*?)(?=--path|$)/; const registryPlugins = argsAsString.match(regexRegistryPlugins)?.[0]?.split(" ")?.filter(s => s) || []; From 3e5475f70d2c3914bb92f26075af957c4300004b Mon Sep 17 00:00:00 2001 From: SamTV12345 <40429738+SamTV12345@users.noreply.github.com> Date: Mon, 25 Aug 2025 21:06:11 +0200 Subject: [PATCH 5/5] chore: added prometheus support in Etherpad (#7095) --- pnpm-lock.yaml | 30 ++++++++++++++++++++++++++ src/node/hooks/express/specialpages.ts | 9 ++++++++ src/node/metrics.ts | 11 ++++++++++ src/node/prometheus.ts | 25 +++++++++++++++++++++ src/package.json | 1 + 5 files changed, 76 insertions(+) create mode 100644 src/node/metrics.ts create mode 100644 src/node/prometheus.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 545d9c2a6..8e621552a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -224,6 +224,9 @@ importers: openapi-backend: specifier: ^5.15.0 version: 5.15.0 + prom-client: + specifier: ^15.1.3 + version: 15.1.3 proxy-addr: specifier: ^2.0.7 version: 2.0.7 @@ -832,6 +835,10 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + '@paralleldrive/cuid2@2.2.2': resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} @@ -2073,6 +2080,9 @@ packages: binary-search@1.3.6: resolution: {integrity: sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==} + bintrees@1.0.2: + resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} + birpc@2.5.0: resolution: {integrity: sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==} @@ -3825,6 +3835,10 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prom-client@15.1.3: + resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==} + engines: {node: ^16 || ^18 || >=20} + promise@1.3.0: resolution: {integrity: sha512-R9WrbTF3EPkVtWjp7B7umQGVndpsi+rsDAfrR4xAALQpFLa/+2OriecLhawxzvii2gd9+DZFwROWDuUUaqS5yA==} @@ -4376,6 +4390,9 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + tdigest@0.1.2: + resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -5252,6 +5269,8 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@opentelemetry/api@1.9.0': {} + '@paralleldrive/cuid2@2.2.2': dependencies: '@noble/hashes': 1.8.0 @@ -6491,6 +6510,8 @@ snapshots: binary-search@1.3.6: {} + bintrees@1.0.2: {} + birpc@2.5.0: {} body-parser@2.2.0: @@ -8499,6 +8520,11 @@ snapshots: prelude-ls@1.2.1: {} + prom-client@15.1.3: + dependencies: + '@opentelemetry/api': 1.9.0 + tdigest: 0.1.2 + promise@1.3.0: dependencies: is-promise: 1.0.1 @@ -9141,6 +9167,10 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 + tdigest@0.1.2: + dependencies: + bintrees: 1.0.2 + tinybench@2.9.0: {} tinycon@0.6.8: {} diff --git a/src/node/hooks/express/specialpages.ts b/src/node/hooks/express/specialpages.ts index 8d42a43bb..1f4ce3302 100644 --- a/src/node/hooks/express/specialpages.ts +++ b/src/node/hooks/express/specialpages.ts @@ -13,8 +13,11 @@ const plugins = require('../../../static/js/pluginfw/plugin_defs'); import {build, buildSync} from 'esbuild' import {ArgsExpressType} from "../../types/ArgsExpressType"; +import prometheus from "../../prometheus"; + let ioI: { sockets: { sockets: any[]; }; } | null = null + exports.socketio = (hookName: string, {io}: any) => { ioI = io } @@ -35,6 +38,12 @@ exports.expressPreSession = async (hookName:string, {app}:ArgsExpressType) => { app.get('/stats', (req:any, res:any) => { res.json(require('../../stats').toJSON()); }); + + app.get('/stats/prometheus', async (req, res) => { + const metrics = await prometheus() + res.setHeader('Content-Type', metrics.contentType) + res.send(await metrics.metrics()) + }) } diff --git a/src/node/metrics.ts b/src/node/metrics.ts new file mode 100644 index 000000000..5afc72654 --- /dev/null +++ b/src/node/metrics.ts @@ -0,0 +1,11 @@ +import Prometheus from 'prom-client'; + +export const metrics = { + 'cpu': new Prometheus.Gauge({ name: 'nodejs_cpu_gauge', help: 'gauge for nodejs cpu' ,labelNames: ['type'] }), + 'memory_process': new Prometheus.Gauge({ name: 'nodejs_memory_process_gauge', help: 'gauge for nodejs memory_process' ,labelNames: ['type'] }), + 'memory_physical': new Prometheus.Gauge({ name: 'nodejs_memory_physical_gauge', help: 'gauge for nodejs_memory_physical' ,labelNames: ['type'] }), + 'eventloop_latency': new Prometheus.Gauge({ name: 'nodejs_eventloop_latency_gauge' , help: 'gauge for nodejs_eventloop_latency' ,labelNames: ['type'] }), + 'gc': new Prometheus.Gauge({ name: 'nodejs_gc_gauge' , help: 'gause for nodejs_gc' ,labelNames: ['type']}), + 'gc_duration': new Prometheus.Summary({ name: 'nodejs_gc_duration' , help: 'gause for nodejs_gc_duration', percentiles: [ 0.5, 0.75, 0.95 ] }), + 'http_duration': new Prometheus.Summary({ name: 'http_duration', help: 'summary for http_duration', percentiles: [ 0.5, 0.75, 0.95 ] ,labelNames: ['url'] }) +}; diff --git a/src/node/prometheus.ts b/src/node/prometheus.ts new file mode 100644 index 000000000..2fad567f4 --- /dev/null +++ b/src/node/prometheus.ts @@ -0,0 +1,25 @@ +import client from 'prom-client' +const db = require('./db/DB').db + +const monitor = function () { + const collectDefaultMetrics = client.collectDefaultMetrics; + const Registry = client.Registry; + const register = new Registry(); + collectDefaultMetrics({register}); + const gaugeDB = new client.Gauge({ + name: "ueberdb_stats", + help: "ueberdb stats", + labelNames: ['type'], + }) + + for (const [metric, value] of Object.entries(db.metrics)) { + if (typeof value !== 'number') continue; + gaugeDB.set({type: metric}, value); + } + + + register.registerMetric(gaugeDB); + return register +}; + +export default monitor; diff --git a/src/package.json b/src/package.json index d8097591f..18f3d9ad0 100644 --- a/src/package.json +++ b/src/package.json @@ -58,6 +58,7 @@ "mime-types": "^3.0.1", "oidc-provider": "^9.4.2", "openapi-backend": "^5.15.0", + "prom-client": "^15.1.3", "proxy-addr": "^2.0.7", "rate-limiter-flexible": "^7.2.0", "rehype": "^13.0.2",