openvibers/openvibe.wiki Commits
The SQLite era is gone (on PostgreSQL since 2026-09-28; no compatibility kept): the one-time migrate-to-postgres script, WIKI_DB_PATH/dbPath (config, .env.example, systemd unit, test helpers), the unused better-sqlite3 dependency and its lockfile entries, and docs, docstrings and STATUS lines about SQLite or its rollback window. Reviewed independently (VERDICT: SHIP). npm test 32/32 test files passed.
Changes
@@@ -1,7 +1,7 @@# ═══════════════════════════════════════════════════════════════# OpenVibe.Wiki — Environment Configuration# Copy to .env and fill in values. In production this lives at /etc/openvibe/wiki.env (0600);--# the systemd unit sets NODE_ENV, PORT and WIKI_DB_PATH itself. Names only here: never commit values.++# the systemd unit sets NODE_ENV and PORT itself. Names only here: never commit values.# ═══════════════════════════════════════════════════════════════# Server@@@ -17,16 +17,13 @@ NODE_ENV=development#WIKI_LIMITS_MINUTE=120#WIKI_LIMITS_HOUR=3000--# Store (SQLite, WAL). Production: /var/lib/openvibe-wiki/wiki.db (systemd StateDirectory).--# PostgreSQL (ADR-035), written by OpenVibe.Host roles/data/add-service.sh wiki: the runtime role through PgBouncer,--# the owner on a direct connection (migrations and the one-time import), and Valkey (shared limit counters).++# Store: PostgreSQL (ADR-035), written by OpenVibe.Host roles/data/add-service.sh wiki — the runtime role through++# PgBouncer, the owner on a direct connection (migrations), and Valkey (shared limit counters).# Without DATABASE_URL, development uses an embedded PGlite database in data/pglite.DATABASE_URL=DATABASE_DIRECT_URL=VALKEY_URL=VALKEY_PREFIX=--# The SQLite file of releases before PostgreSQL: read once by scripts/migrate-to-postgres.js.--WIKI_DB_PATH=./data/wiki.db# Identity — OpenVibe.Network signs user JWTs (SSO) and service tokens. The public key is fetched# from <url>/api/.well-known/jwks (internal URL first) and retried every 30 s until it loads.@@@ -3,9 +3,6 @@ data/.env.env.*!.env.example--*.db--*.db-wal--*.db-shm*.log*.pem*.key@@@ -77,8 +77,6 @@ records who attached each Media object and what Media said about it at that momeEvery doubt refuses.- *Where it never shows:* search, sitemaps, feeds, and another viewer's lists.- *Official spaces* have no VIP owner and refuse `vip`.-- - *Migration:* databases made before it get their visibility CHECK widened in place at startup-- (`widenVisibilityChecks`, integrity-checked).- Config: `OV_VIP_INTERNAL_URL`, `OV_VIP_URL`, and `WIKI_VIP_*` for the timeout and cache.- **Pages**: a tree per space, canonical slugs, rename/move with history-aware 301s (chainscollapse; renaming a space redirects all its pages), deletion answers 410 at every old address.@@@ -347,9 +345,7 @@ Production deploys with `sudo ovhost deploy wiki` on the host (strategy `git-chefast-forward `/opt/openvibe.wiki`, install on a lockfile change, restart, wait for `/api/ready`).The unit is `openvibe-wiki.service` on `127.0.0.1:4800`, the env file `/etc/openvibe/wiki.env`. The database is`ov_wiki` on the host's data role (`sudo /opt/openvibe.host/roles/data/add-service.sh wiki` writes its settings);--the release migrates it at boot. The one-time move from SQLite is `scripts/migrate-to-postgres.js` (openvibe-sdk--`runSqliteMigration`: import, verification, and a rehearsal mode `--pglite`), run while the service is stopped;--the old `/var/lib/openvibe-wiki/wiki.db` stays read-only for 7 days as the rollback. nginx serves `openvibe.wiki` from++the release migrates it at boot. nginx serves `openvibe.wiki` from[deploy/nginx/openvibe.wiki.conf](deploy/nginx/openvibe.wiki.conf).Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after therestart; afterwards `sudo ovhost rollback wiki --to <sha>`. Nothing blocks a rollback: the schema@@@ -44,5 +44,5 @@"SDK outbox events and Search index documents","per-actor limits (openvibe-sdk/limits)"],-- "database": "PostgreSQL ov_wiki (ADR-035), schema migrations/0001_initial.sql; the SQLite file of earlier releases is imported once by scripts/migrate-to-postgres.js and kept read-only 7 days"++ "database": "PostgreSQL ov_wiki (ADR-035), schema migrations/0001_initial.sql"}@@@ -24,9 +24,6 @@ NoNewPrivileges=truePrivateTmp=trueProtectSystem=strictProtectHome=true--# The code tree stays read-only; the database lives in /var/lib/openvibe-wiki.--StateDirectory=openvibe-wiki--Environment=WIKI_DB_PATH=/var/lib/openvibe-wiki/wiki.db[Install]WantedBy=multi-user.target@@@ -166,8 +166,8 @@ Network), per-account quotas, Turnstile on `/new-space`, a staff takedown that s## 7. Revisions and vandalism--- Revisions, citations, infobox values and link rows are immutable in SQLite triggers-- (`node_modules/openvibe-publishing/lib/internal.js:97-104`, `server/db.js:91-97` and `:148-149` for Wiki's tables);++- Revisions, citations, infobox values and link rows are immutable in database triggers++ (`node_modules/openvibe-publishing/lib/internal.js:97-104`, `migrations/0001_initial.sql` for Wiki's tables);revert is a new revision (`server/wiki/service.js:708`); edits need `expected_revision` andconflict with 412 (`server/wiki/service.js:683`, `test/revisions.test.js`).- Who may vandalise is small by design: editors appointed by the space owner, staff in official@@@ -9,7 +9,6 @@"version": "0.1.0","license": "AGPL-3.0-only","dependencies": {-- "better-sqlite3": "^11.10.0","cookie-parser": "^1.4.7","dotenv": "^16.4.7","express": "^4.21.2",@@@ -111,7 +110,9 @@"url": "https://feross.org/support"}],-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/better-sqlite3": {"version": "11.10.0",@@@ -119,6 +120,8 @@"integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==","hasInstallScript": true,"license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"bindings": "^1.5.0","prebuild-install": "^7.1.1"@@@ -129,6 +132,8 @@"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz","integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"file-uri-to-path": "1.0.0"}@@@ -138,6 +143,8 @@"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz","integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"buffer": "^5.5.0","inherits": "^2.0.4",@@@ -187,6 +194,8 @@}],"license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"base64-js": "^1.3.1","ieee754": "^1.1.13"@@@ -240,7 +249,9 @@"version": "1.1.4","resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz","integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",-- "license": "ISC"++ "license": "ISC",++ "optional": true,++ "peer": true},"node_modules/cluster-key-slot": {"version": "1.1.2",@@@ -314,6 +325,8 @@"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz","integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"mimic-response": "^3.1.0"},@@@ -329,6 +342,8 @@"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz","integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==","license": "MIT",++ "optional": true,++ "peer": true,"engines": {"node": ">=4.0.0"}@@@ -366,6 +381,8 @@"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz","integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==","license": "Apache-2.0",++ "optional": true,++ "peer": true,"engines": {"node": ">=8"}@@@ -425,6 +442,8 @@"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz","integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"once": "^1.4.0"}@@@ -479,6 +498,8 @@"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz","integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==","license": "(MIT OR WTFPL)",++ "optional": true,++ "peer": true,"engines": {"node": ">=6"}@@@ -570,7 +591,9 @@"version": "1.0.0","resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz","integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/finalhandler": {"version": "1.3.2",@@@ -612,7 +635,9 @@"version": "1.0.0","resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz","integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/function-bind": {"version": "1.1.2",@@@ -664,7 +689,9 @@"version": "0.0.0","resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz","integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/gopd": {"version": "1.2.0",@@@ -752,7 +779,9 @@"url": "https://feross.org/support"}],-- "license": "BSD-3-Clause"++ "license": "BSD-3-Clause",++ "optional": true,++ "peer": true},"node_modules/inherits": {"version": "2.0.4",@@@ -764,7 +793,9 @@"version": "1.3.8","resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz","integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",-- "license": "ISC"++ "license": "ISC",++ "optional": true,++ "peer": true},"node_modules/iovalkey": {"version": "0.4.0",@@@ -1001,6 +1032,8 @@"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz","integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==","license": "MIT",++ "optional": true,++ "peer": true,"engines": {"node": ">=10"},@@@ -1013,6 +1046,8 @@"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz","integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==","license": "MIT",++ "optional": true,++ "peer": true,"funding": {"url": "https://github.com/sponsors/ljharb"}@@@ -1021,7 +1056,9 @@"version": "0.5.3","resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz","integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/ms": {"version": "2.0.0",@@@ -1033,7 +1070,9 @@"version": "2.0.0","resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz","integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/negotiator": {"version": "0.6.3",@@@ -1049,6 +1088,8 @@"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.96.0.tgz","integrity": "sha512-rebQ/lz7i0EkoLzUVSrKRzA69zMkwLp95kKMWoMDkkM00Suxz0D7zEQPwRml5fQum24mj7bPvmlgLAmu2JCiYg==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"semver": "^7.3.5"},@@@ -1085,6 +1126,8 @@"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz","integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==","license": "ISC",++ "optional": true,++ "peer": true,"dependencies": {"wrappy": "1"}@@@ -1310,6 +1353,8 @@"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==","deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"detect-libc": "^2.0.0","expand-template": "^2.0.3",@@@ -1353,6 +1398,8 @@"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz","integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"end-of-stream": "^1.1.0","once": "^1.3.1"@@@ -1403,6 +1450,8 @@"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz","integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==","license": "(BSD-2-Clause OR MIT OR Apache-2.0)",++ "optional": true,++ "peer": true,"dependencies": {"deep-extend": "^0.6.0","ini": "~1.3.0",@@@ -1418,6 +1467,8 @@"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz","integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"inherits": "^2.0.3","string_decoder": "^1.1.1",@@@ -1636,7 +1687,9 @@"url": "https://feross.org/support"}],-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/simple-get": {"version": "4.0.1",@@@ -1657,6 +1710,8 @@}],"license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"decompress-response": "^6.0.0","once": "^1.3.1",@@@ -1692,6 +1747,8 @@"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz","integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"safe-buffer": "~5.2.0"}@@@ -1701,6 +1758,8 @@"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz","integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==","license": "MIT",++ "optional": true,++ "peer": true,"engines": {"node": ">=0.10.0"}@@@ -1710,6 +1769,8 @@"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz","integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"chownr": "^1.1.1","mkdirp-classic": "^0.5.2",@@@ -1722,6 +1783,8 @@"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz","integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==","license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"bl": "^4.0.3","end-of-stream": "^1.4.1",@@@ -1747,6 +1810,8 @@"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz","integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==","license": "Apache-2.0",++ "optional": true,++ "peer": true,"dependencies": {"safe-buffer": "^5.0.1"},@@@ -1780,7 +1845,9 @@"version": "1.0.2","resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz","integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/utils-merge": {"version": "1.0.1",@@@ -1804,7 +1871,9 @@"version": "1.0.2","resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz","integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",-- "license": "ISC"++ "license": "ISC",++ "optional": true,++ "peer": true},"node_modules/xtend": {"version": "4.0.2",@@@ -9,8 +9,7 @@"dev": "NODE_ENV=development node server/index.js","seed": "node scripts/seed.js","test": "node test/run.js",-- "test:pg": "WIKI_TEST_STORE=pg node test/run.js",-- "migrate-to-postgres": "node scripts/migrate-to-postgres.js"++ "test:pg": "WIKI_TEST_STORE=pg node test/run.js"},"keywords": ["openvibe",@@@ -21,7 +20,6 @@"license": "AGPL-3.0-only","repository": "github:OpenVibers/OpenVibe.Wiki","dependencies": {-- "better-sqlite3": "^11.10.0","cookie-parser": "^1.4.7","dotenv": "^16.4.7","express": "^4.21.2",ddeleted file mode 100644@@@ -1,31 +0,0 @@--#!/usr/bin/env node--'use strict';--/**-- * The one-time move of Wiki's SQLite database (WIKI_DB_PATH) into its PostgreSQL schema (ADR-035; the procedure-- * is openvibe-sdk docs/migrating-to-postgresql.md, section 6, carried out by openvibe-sdk/db runSqliteMigration).-- *-- * node scripts/migrate-to-postgres.js [--sqlite <file>] [--pglite] [--json]-- *-- * Applies migrations/ as the owner (DATABASE_DIRECT_URL), copies every table into emptied tables, verifies row-- * counts and checksums, and exits 1 unless everything verified. The SQLite file is opened read-only. In-- * production it runs once, from the new release's directory, as the service user with the service's-- * environment, while the service is stopped (the write freeze), before the PostgreSQL release starts.-- *-- * Every table keeps its name and columns. What the SQLite file holds that PostgreSQL does not take:-- * the SDK's SQLite outbox bookkeeping becomes the PostgreSQL outbox's (wiki_event_outbox: same rows; lease-- * columns start empty), and SQLite's own tables (sqlite_sequence) are not copied.-- */--require('dotenv').config();--const { runSqliteMigration } = require('openvibe-sdk/db');--const { load } = require('../server/config');--const { MIGRATIONS } = require('../server/db');----const TABLES = {};----if (require.main === module) {-- const config = load();-- runSqliteMigration({ service: 'wiki', sqlite: config.dbPath, directUrl: config.db.directUrl, migrations: MIGRATIONS, tables: TABLES })-- .then((code) => process.exit(code), (err) => { console.error(`migrate-to-postgres failed: ${err.message}`); process.exit(1); });--}----module.exports = { TABLES };@@@ -33,8 +33,6 @@ function load(env = process.env) {// PostgreSQL (ADR-035): DATABASE_URL serves (PgBouncer), DATABASE_DIRECT_URL migrates (owner role).db: { url: env.DATABASE_URL || '', directUrl: env.DATABASE_DIRECT_URL || '' },valkey: { url: env.VALKEY_URL || '', prefix: env.VALKEY_PREFIX || 'ov:wiki:' },-- // The SQLite file of releases before the switch: read once by scripts/migrate-to-postgres.js.-- dbPath: env.WIKI_DB_PATH || './data/wiki.db',// Identity: OpenVibe.Network signs user JWTs (SSO) and service tokens (client credentials).networkUrl,@@@ -75,11 +75,10 @@ function createWikiService({ db, stores, outbox, config, community = null, vip =const access = createAccess(db, { vip });const origin = config.baseUrl;const policy = config.gate;-- // Every entry point reads the actor's roles again (one indexed query): a role granted a moment ago counts, as-- // it did when each check read SQLite.++ // Every entry point reads the actor's roles again (one indexed query): a role granted a moment ago counts.const roles = (actor, opts = { fresh: true }) => access.loadRoles(actor, opts);-- // ── Queries (PostgreSQL; better-sqlite3-shaped async statements, openvibe-sdk/db prepare) ──++ // ── Queries (PostgreSQL; async prepared statements via openvibe-sdk/db prepare) ──const q = {spaceById: db.prepare('SELECT * FROM wiki_spaces WHERE id = ?'),spacesByIds: db.prepare('SELECT * FROM wiki_spaces WHERE id = ANY(?)'),@@@ -134,7 +133,7 @@ function createWikiService({ db, stores, outbox, config, community = null, vip =insertOrigin: db.prepare(`INSERT INTO wiki_attachment_origins (attachment_id, page_id, media_id, attached_by, media_owner, media_visibility, attached_at)VALUES (?, ?, ?, ?, ?, ?, ?)`),originsOf: db.prepare('SELECT * FROM wiki_attachment_origins WHERE page_id = ?'),-- // Case-insensitive, as SQLite's LIKE was for ASCII.++ // Case-insensitive title and content search.search: db.prepare(`SELECT p.* FROM wiki_pages p JOIN wiki_spaces s ON s.id = p.space_idJOIN wiki_page_revisions r ON r.entity_id = p.id AND r.number = p.published_revisionWHERE p.state = 'published' AND s.deleted_at IS NULL AND (@space::text IS NULL OR s.slug = @space)@@@ -4,9 +4,6 @@* key, signed user JWTs and service tokens, and a stub fetch for the other services.*/const crypto = require('crypto');--const fs = require('fs');--const os = require('os');--const path = require('path');const { serviceAuth } = require('openvibe-contracts');const { load } = require('../server/config');const { start } = require('../server/index');@@@ -43,13 +40,11 @@ const quiet = process.env.WIKI_TEST_LOG ? console : { log() {}, warn() {}, error* A running Wiki on a database of its own (PGlite by default; WIKI_TEST_STORE=pg: the PostgreSQL + PgBouncer* containers). opts.db: boot on an existing handle (a restart keeps the data); h.stop() closes what boot opened.*/--async function boot({ env = {}, fetch: fetchImpl, dbPath, db: givenDb = null, now, workers = false, tokens, rateLimits = false, limitsNow = null, log = quiet } = {}) {-- const dir = dbPath ? path.dirname(dbPath) : fs.mkdtempSync(path.join(os.tmpdir(), 'wiki-test-'));++async function boot({ env = {}, fetch: fetchImpl, db: givenDb = null, now, workers = false, tokens, rateLimits = false, limitsNow = null, log = quiet } = {}) {const owned = givenDb ? null : await testDb();const db = givenDb || owned.db;const config = load({NODE_ENV: 'test', PORT: '0', HOST: '127.0.0.1', BASE_URL: 'http://wiki.test',-- WIKI_DB_PATH: dbPath || path.join(dir, 'wiki.db'),OV_NETWORK_URL: ISSUER, OV_NETWORK_INTERNAL_URL: '', WIKI_GATE_MIN_WORDS: '20',...env,});@@@ -60,7 +55,7 @@ async function boot({ env = {}, fetch: fetchImpl, dbPath, db: givenDb = null, no});const base = `http://127.0.0.1:${h.server.address().port}`;const stop = async ({ keepDb = false } = {}) => { await h.stop(); if (owned && !keepDb) await owned.close(); };-- return { ...h, stop, base, dir, dbPath: config.dbPath, closeDb: owned ? owned.close : async () => {} };++ return { ...h, stop, base, closeDb: owned ? owned.close : async () => {} };}async function req(h, method, p, { token, body, form, headers = {}, cookie } = {}) {@@@ -4,8 +4,6 @@// measurement; raising one is a decision to state in the commit.// node test/perf-budget.test.jsconst assert = require('assert');--const fs = require('fs');--const os = require('os');const net = require('net');const path = require('path');const { spawn } = require('child_process');@@@ -26,11 +24,10 @@ const BUDGETS = {const freePort = () => new Promise((resolve) => { const s = net.createServer(); s.listen(0, '127.0.0.1', () => { const { port } = s.address(); s.close(() => resolve(port)); }); });(async () => {-- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ov-budget-'));const port = await freePort();const child = spawn(process.execPath, [path.join(__dirname, '..', 'server', 'index.js')], {cwd: path.join(__dirname, '..'),-- env: { ...process.env, PORT: String(port), HOST: '127.0.0.1', NODE_ENV: 'test', WIKI_DB_PATH: path.join(dir, 'wiki.db') },++ env: { ...process.env, PORT: String(port), HOST: '127.0.0.1', NODE_ENV: 'test' },stdio: ['ignore', 'ignore', 'pipe'],});let stderr = '';@@@ -50,6 +47,5 @@ const freePort = () => new Promise((resolve) => { const s = net.createServer();console.log('perf budget: all checks passed');} finally {child.kill();-- fs.rmSync(dir, { recursive: true, force: true });}})().catch((err) => { console.error(err); process.exitCode = 1; });@@@ -1,7 +1,7 @@#!/usr/bin/env node/*** Runs every test in test/ — the files named *.test.js — each in its own process, and fails if-- * any of them fails. They use temp SQLite databases, a generated RSA key and stub upstreams; none++ * any of them fails. They use temporary PGlite (PostgreSQL) databases, a generated RSA key and stub upstreams; none* of them needs the network or a running OpenVibe service.** npm test # everything@@@ -14,7 +14,7 @@ const VIP_URL = 'http://127.0.0.1:4620/api/v1/policies/evaluate';(async () => {// The schema: `vip` is a visibility PostgreSQL accepts, and anything else is still refused by the CHECK-- // (on SQLite a database made before `vip` was widened in place; migrations/0001 has it from the start).++ // (migrations/0001 defines it from the start).{const { testDb } = require('./db-helper');const { db, close } = await testDb();
@@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
# OpenVibe.Wiki — Environment Configuration
# OpenVibe.Wiki — Environment Configuration
# Copy to .env and fill in values. In production this lives at /etc/openvibe/wiki.env (0600);
# Copy to .env and fill in values. In production this lives at /etc/openvibe/wiki.env (0600);
-# the systemd unit sets NODE_ENV, PORT and WIKI_DB_PATH itself. Names only here: never commit values.
+# the systemd unit sets NODE_ENV and PORT itself. Names only here: never commit values.
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
# Server
# Server
@@ -17,16 +17,13 @@ NODE_ENV=development
@@ -17,16 +17,13 @@ NODE_ENV=development
#WIKI_LIMITS_MINUTE=120
#WIKI_LIMITS_MINUTE=120
#WIKI_LIMITS_HOUR=3000
#WIKI_LIMITS_HOUR=3000
-# Store (SQLite, WAL). Production: /var/lib/openvibe-wiki/wiki.db (systemd StateDirectory).
-# PostgreSQL (ADR-035), written by OpenVibe.Host roles/data/add-service.sh wiki: the runtime role through PgBouncer,
-# the owner on a direct connection (migrations and the one-time import), and Valkey (shared limit counters).
+# Store: PostgreSQL (ADR-035), written by OpenVibe.Host roles/data/add-service.sh wiki — the runtime role through
+# PgBouncer, the owner on a direct connection (migrations), and Valkey (shared limit counters).
# Without DATABASE_URL, development uses an embedded PGlite database in data/pglite.
# Without DATABASE_URL, development uses an embedded PGlite database in data/pglite.
DATABASE_URL=
DATABASE_URL=
DATABASE_DIRECT_URL=
DATABASE_DIRECT_URL=
VALKEY_URL=
VALKEY_URL=
VALKEY_PREFIX=
VALKEY_PREFIX=
-# The SQLite file of releases before PostgreSQL: read once by scripts/migrate-to-postgres.js.
-WIKI_DB_PATH=./data/wiki.db
# Identity — OpenVibe.Network signs user JWTs (SSO) and service tokens. The public key is fetched
# Identity — OpenVibe.Network signs user JWTs (SSO) and service tokens. The public key is fetched
# from <url>/api/.well-known/jwks (internal URL first) and retried every 30 s until it loads.
# from <url>/api/.well-known/jwks (internal URL first) and retried every 30 s until it loads.
@@ -3,9 +3,6 @@ data/
@@ -3,9 +3,6 @@ data/
.env
.env
.env.*
.env.*
!.env.example
!.env.example
-*.db
-*.db-wal
-*.db-shm
*.log
*.log
*.pem
*.pem
*.key
*.key
@@ -77,8 +77,6 @@ records who attached each Media object and what Media said about it at that mome
@@ -77,8 +77,6 @@ records who attached each Media object and what Media said about it at that mome
Every doubt refuses.
Every doubt refuses.
- *Where it never shows:* search, sitemaps, feeds, and another viewer's lists.
- *Where it never shows:* search, sitemaps, feeds, and another viewer's lists.
- *Official spaces* have no VIP owner and refuse `vip`.
- *Official spaces* have no VIP owner and refuse `vip`.
- - *Migration:* databases made before it get their visibility CHECK widened in place at startup
- (`widenVisibilityChecks`, integrity-checked).
- Config: `OV_VIP_INTERNAL_URL`, `OV_VIP_URL`, and `WIKI_VIP_*` for the timeout and cache.
- Config: `OV_VIP_INTERNAL_URL`, `OV_VIP_URL`, and `WIKI_VIP_*` for the timeout and cache.
- **Pages**: a tree per space, canonical slugs, rename/move with history-aware 301s (chains
- **Pages**: a tree per space, canonical slugs, rename/move with history-aware 301s (chains
collapse; renaming a space redirects all its pages), deletion answers 410 at every old address.
collapse; renaming a space redirects all its pages), deletion answers 410 at every old address.
@@ -347,9 +345,7 @@ Production deploys with `sudo ovhost deploy wiki` on the host (strategy `git-che
@@ -347,9 +345,7 @@ Production deploys with `sudo ovhost deploy wiki` on the host (strategy `git-che
fast-forward `/opt/openvibe.wiki`, install on a lockfile change, restart, wait for `/api/ready`).
fast-forward `/opt/openvibe.wiki`, install on a lockfile change, restart, wait for `/api/ready`).
The unit is `openvibe-wiki.service` on `127.0.0.1:4800`, the env file `/etc/openvibe/wiki.env`. The database is
The unit is `openvibe-wiki.service` on `127.0.0.1:4800`, the env file `/etc/openvibe/wiki.env`. The database is
`ov_wiki` on the host's data role (`sudo /opt/openvibe.host/roles/data/add-service.sh wiki` writes its settings);
`ov_wiki` on the host's data role (`sudo /opt/openvibe.host/roles/data/add-service.sh wiki` writes its settings);
-the release migrates it at boot. The one-time move from SQLite is `scripts/migrate-to-postgres.js` (openvibe-sdk
-`runSqliteMigration`: import, verification, and a rehearsal mode `--pglite`), run while the service is stopped;
-the old `/var/lib/openvibe-wiki/wiki.db` stays read-only for 7 days as the rollback. nginx serves `openvibe.wiki` from
+the release migrates it at boot. nginx serves `openvibe.wiki` from
[deploy/nginx/openvibe.wiki.conf](deploy/nginx/openvibe.wiki.conf).
[deploy/nginx/openvibe.wiki.conf](deploy/nginx/openvibe.wiki.conf).
Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after the
Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after the
restart; afterwards `sudo ovhost rollback wiki --to <sha>`. Nothing blocks a rollback: the schema
restart; afterwards `sudo ovhost rollback wiki --to <sha>`. Nothing blocks a rollback: the schema
@@ -44,5 +44,5 @@
@@ -44,5 +44,5 @@
"SDK outbox events and Search index documents",
"SDK outbox events and Search index documents",
"per-actor limits (openvibe-sdk/limits)"
"per-actor limits (openvibe-sdk/limits)"
],
],
- "database": "PostgreSQL ov_wiki (ADR-035), schema migrations/0001_initial.sql; the SQLite file of earlier releases is imported once by scripts/migrate-to-postgres.js and kept read-only 7 days"
+ "database": "PostgreSQL ov_wiki (ADR-035), schema migrations/0001_initial.sql"
}
}
@@ -24,9 +24,6 @@ NoNewPrivileges=true
@@ -24,9 +24,6 @@ NoNewPrivileges=true
PrivateTmp=true
PrivateTmp=true
ProtectSystem=strict
ProtectSystem=strict
ProtectHome=true
ProtectHome=true
-# The code tree stays read-only; the database lives in /var/lib/openvibe-wiki.
-StateDirectory=openvibe-wiki
-Environment=WIKI_DB_PATH=/var/lib/openvibe-wiki/wiki.db
[Install]
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target
@@ -166,8 +166,8 @@ Network), per-account quotas, Turnstile on `/new-space`, a staff takedown that s
@@ -166,8 +166,8 @@ Network), per-account quotas, Turnstile on `/new-space`, a staff takedown that s
## 7. Revisions and vandalism
## 7. Revisions and vandalism
-- Revisions, citations, infobox values and link rows are immutable in SQLite triggers
- (`node_modules/openvibe-publishing/lib/internal.js:97-104`, `server/db.js:91-97` and `:148-149` for Wiki's tables);
+- Revisions, citations, infobox values and link rows are immutable in database triggers
+ (`node_modules/openvibe-publishing/lib/internal.js:97-104`, `migrations/0001_initial.sql` for Wiki's tables);
revert is a new revision (`server/wiki/service.js:708`); edits need `expected_revision` and
revert is a new revision (`server/wiki/service.js:708`); edits need `expected_revision` and
conflict with 412 (`server/wiki/service.js:683`, `test/revisions.test.js`).
conflict with 412 (`server/wiki/service.js:683`, `test/revisions.test.js`).
- Who may vandalise is small by design: editors appointed by the space owner, staff in official
- Who may vandalise is small by design: editors appointed by the space owner, staff in official
@@ -9,7 +9,6 @@
@@ -9,7 +9,6 @@
"version": "0.1.0",
"version": "0.1.0",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
- "better-sqlite3": "^11.10.0",
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
"dotenv": "^16.4.7",
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express": "^4.21.2",
@@ -111,7 +110,9 @@
@@ -111,7 +110,9 @@
"url": "https://feross.org/support"
"url": "https://feross.org/support"
}
}
],
],
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
},
"node_modules/better-sqlite3": {
"node_modules/better-sqlite3": {
"version": "11.10.0",
"version": "11.10.0",
@@ -119,6 +120,8 @@
@@ -119,6 +120,8 @@
"integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==",
"integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==",
"hasInstallScript": true,
"hasInstallScript": true,
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"bindings": "^1.5.0",
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
"prebuild-install": "^7.1.1"
@@ -129,6 +132,8 @@
@@ -129,6 +132,8 @@
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"file-uri-to-path": "1.0.0"
"file-uri-to-path": "1.0.0"
}
}
@@ -138,6 +143,8 @@
@@ -138,6 +143,8 @@
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"buffer": "^5.5.0",
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"inherits": "^2.0.4",
@@ -187,6 +194,8 @@
@@ -187,6 +194,8 @@
}
}
],
],
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"base64-js": "^1.3.1",
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
"ieee754": "^1.1.13"
@@ -240,7 +249,9 @@
@@ -240,7 +249,9 @@
"version": "1.1.4",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
- "license": "ISC"
+ "license": "ISC",
+ "optional": true,
+ "peer": true
},
},
"node_modules/cluster-key-slot": {
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"version": "1.1.2",
@@ -314,6 +325,8 @@
@@ -314,6 +325,8 @@
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"mimic-response": "^3.1.0"
"mimic-response": "^3.1.0"
},
},
@@ -329,6 +342,8 @@
@@ -329,6 +342,8 @@
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"engines": {
"node": ">=4.0.0"
"node": ">=4.0.0"
}
}
@@ -366,6 +381,8 @@
@@ -366,6 +381,8 @@
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"license": "Apache-2.0",
"license": "Apache-2.0",
+ "optional": true,
+ "peer": true,
"engines": {
"engines": {
"node": ">=8"
"node": ">=8"
}
}
@@ -425,6 +442,8 @@
@@ -425,6 +442,8 @@
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"once": "^1.4.0"
"once": "^1.4.0"
}
}
@@ -479,6 +498,8 @@
@@ -479,6 +498,8 @@
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
"license": "(MIT OR WTFPL)",
"license": "(MIT OR WTFPL)",
+ "optional": true,
+ "peer": true,
"engines": {
"engines": {
"node": ">=6"
"node": ">=6"
}
}
@@ -570,7 +591,9 @@
@@ -570,7 +591,9 @@
"version": "1.0.0",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
},
"node_modules/finalhandler": {
"node_modules/finalhandler": {
"version": "1.3.2",
"version": "1.3.2",
@@ -612,7 +635,9 @@
@@ -612,7 +635,9 @@
"version": "1.0.0",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
},
"node_modules/function-bind": {
"node_modules/function-bind": {
"version": "1.1.2",
"version": "1.1.2",
@@ -664,7 +689,9 @@
@@ -664,7 +689,9 @@
"version": "0.0.0",
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
},
"node_modules/gopd": {
"node_modules/gopd": {
"version": "1.2.0",
"version": "1.2.0",
@@ -752,7 +779,9 @@
@@ -752,7 +779,9 @@
"url": "https://feross.org/support"
"url": "https://feross.org/support"
}
}
],
],
- "license": "BSD-3-Clause"
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "peer": true
},
},
"node_modules/inherits": {
"node_modules/inherits": {
"version": "2.0.4",
"version": "2.0.4",
@@ -764,7 +793,9 @@
@@ -764,7 +793,9 @@
"version": "1.3.8",
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
- "license": "ISC"
+ "license": "ISC",
+ "optional": true,
+ "peer": true
},
},
"node_modules/iovalkey": {
"node_modules/iovalkey": {
"version": "0.4.0",
"version": "0.4.0",
@@ -1001,6 +1032,8 @@
@@ -1001,6 +1032,8 @@
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"engines": {
"node": ">=10"
"node": ">=10"
},
},
@@ -1013,6 +1046,8 @@
@@ -1013,6 +1046,8 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"funding": {
"funding": {
"url": "https://github.com/sponsors/ljharb"
"url": "https://github.com/sponsors/ljharb"
}
}
@@ -1021,7 +1056,9 @@
@@ -1021,7 +1056,9 @@
"version": "0.5.3",
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
},
"node_modules/ms": {
"node_modules/ms": {
"version": "2.0.0",
"version": "2.0.0",
@@ -1033,7 +1070,9 @@
@@ -1033,7 +1070,9 @@
"version": "2.0.0",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
},
"node_modules/negotiator": {
"node_modules/negotiator": {
"version": "0.6.3",
"version": "0.6.3",
@@ -1049,6 +1088,8 @@
@@ -1049,6 +1088,8 @@
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.96.0.tgz",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.96.0.tgz",
"integrity": "sha512-rebQ/lz7i0EkoLzUVSrKRzA69zMkwLp95kKMWoMDkkM00Suxz0D7zEQPwRml5fQum24mj7bPvmlgLAmu2JCiYg==",
"integrity": "sha512-rebQ/lz7i0EkoLzUVSrKRzA69zMkwLp95kKMWoMDkkM00Suxz0D7zEQPwRml5fQum24mj7bPvmlgLAmu2JCiYg==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"semver": "^7.3.5"
"semver": "^7.3.5"
},
},
@@ -1085,6 +1126,8 @@
@@ -1085,6 +1126,8 @@
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"license": "ISC",
"license": "ISC",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"wrappy": "1"
"wrappy": "1"
}
}
@@ -1310,6 +1353,8 @@
@@ -1310,6 +1353,8 @@
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
"deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
"deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"detect-libc": "^2.0.0",
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
"expand-template": "^2.0.3",
@@ -1353,6 +1398,8 @@
@@ -1353,6 +1398,8 @@
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"end-of-stream": "^1.1.0",
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
"once": "^1.3.1"
@@ -1403,6 +1450,8 @@
@@ -1403,6 +1450,8 @@
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"deep-extend": "^0.6.0",
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"ini": "~1.3.0",
@@ -1418,6 +1467,8 @@
@@ -1418,6 +1467,8 @@
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"inherits": "^2.0.3",
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"string_decoder": "^1.1.1",
@@ -1636,7 +1687,9 @@
@@ -1636,7 +1687,9 @@
"url": "https://feross.org/support"
"url": "https://feross.org/support"
}
}
],
],
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
},
"node_modules/simple-get": {
"node_modules/simple-get": {
"version": "4.0.1",
"version": "4.0.1",
@@ -1657,6 +1710,8 @@
@@ -1657,6 +1710,8 @@
}
}
],
],
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"decompress-response": "^6.0.0",
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"once": "^1.3.1",
@@ -1692,6 +1747,8 @@
@@ -1692,6 +1747,8 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"safe-buffer": "~5.2.0"
"safe-buffer": "~5.2.0"
}
}
@@ -1701,6 +1758,8 @@
@@ -1701,6 +1758,8 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"engines": {
"node": ">=0.10.0"
"node": ">=0.10.0"
}
}
@@ -1710,6 +1769,8 @@
@@ -1710,6 +1769,8 @@
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz",
"integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==",
"integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"chownr": "^1.1.1",
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
"mkdirp-classic": "^0.5.2",
@@ -1722,6 +1783,8 @@
@@ -1722,6 +1783,8 @@
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"license": "MIT",
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"bl": "^4.0.3",
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"end-of-stream": "^1.4.1",
@@ -1747,6 +1810,8 @@
@@ -1747,6 +1810,8 @@
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"license": "Apache-2.0",
"license": "Apache-2.0",
+ "optional": true,
+ "peer": true,
"dependencies": {
"dependencies": {
"safe-buffer": "^5.0.1"
"safe-buffer": "^5.0.1"
},
},
@@ -1780,7 +1845,9 @@
@@ -1780,7 +1845,9 @@
"version": "1.0.2",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
},
"node_modules/utils-merge": {
"node_modules/utils-merge": {
"version": "1.0.1",
"version": "1.0.1",
@@ -1804,7 +1871,9 @@
@@ -1804,7 +1871,9 @@
"version": "1.0.2",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "license": "ISC"
+ "license": "ISC",
+ "optional": true,
+ "peer": true
},
},
"node_modules/xtend": {
"node_modules/xtend": {
"version": "4.0.2",
"version": "4.0.2",
@@ -9,8 +9,7 @@
@@ -9,8 +9,7 @@
"dev": "NODE_ENV=development node server/index.js",
"dev": "NODE_ENV=development node server/index.js",
"seed": "node scripts/seed.js",
"seed": "node scripts/seed.js",
"test": "node test/run.js",
"test": "node test/run.js",
- "test:pg": "WIKI_TEST_STORE=pg node test/run.js",
- "migrate-to-postgres": "node scripts/migrate-to-postgres.js"
+ "test:pg": "WIKI_TEST_STORE=pg node test/run.js"
},
},
"keywords": [
"keywords": [
"openvibe",
"openvibe",
@@ -21,7 +20,6 @@
@@ -21,7 +20,6 @@
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"repository": "github:OpenVibers/OpenVibe.Wiki",
"repository": "github:OpenVibers/OpenVibe.Wiki",
"dependencies": {
"dependencies": {
- "better-sqlite3": "^11.10.0",
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
"dotenv": "^16.4.7",
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express": "^4.21.2",
deleted file mode 100644
deleted file mode 100644
@@ -1,31 +0,0 @@
@@ -1,31 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-/**
- * The one-time move of Wiki's SQLite database (WIKI_DB_PATH) into its PostgreSQL schema (ADR-035; the procedure
- * is openvibe-sdk docs/migrating-to-postgresql.md, section 6, carried out by openvibe-sdk/db runSqliteMigration).
- *
- * node scripts/migrate-to-postgres.js [--sqlite <file>] [--pglite] [--json]
- *
- * Applies migrations/ as the owner (DATABASE_DIRECT_URL), copies every table into emptied tables, verifies row
- * counts and checksums, and exits 1 unless everything verified. The SQLite file is opened read-only. In
- * production it runs once, from the new release's directory, as the service user with the service's
- * environment, while the service is stopped (the write freeze), before the PostgreSQL release starts.
- *
- * Every table keeps its name and columns. What the SQLite file holds that PostgreSQL does not take:
- * the SDK's SQLite outbox bookkeeping becomes the PostgreSQL outbox's (wiki_event_outbox: same rows; lease
- * columns start empty), and SQLite's own tables (sqlite_sequence) are not copied.
- */
-require('dotenv').config();
-const { runSqliteMigration } = require('openvibe-sdk/db');
-const { load } = require('../server/config');
-const { MIGRATIONS } = require('../server/db');
-
-const TABLES = {};
-
-if (require.main === module) {
- const config = load();
- runSqliteMigration({ service: 'wiki', sqlite: config.dbPath, directUrl: config.db.directUrl, migrations: MIGRATIONS, tables: TABLES })
- .then((code) => process.exit(code), (err) => { console.error(`migrate-to-postgres failed: ${err.message}`); process.exit(1); });
-}
-
-module.exports = { TABLES };
@@ -33,8 +33,6 @@ function load(env = process.env) {
@@ -33,8 +33,6 @@ function load(env = process.env) {
// PostgreSQL (ADR-035): DATABASE_URL serves (PgBouncer), DATABASE_DIRECT_URL migrates (owner role).
// PostgreSQL (ADR-035): DATABASE_URL serves (PgBouncer), DATABASE_DIRECT_URL migrates (owner role).
db: { url: env.DATABASE_URL || '', directUrl: env.DATABASE_DIRECT_URL || '' },
db: { url: env.DATABASE_URL || '', directUrl: env.DATABASE_DIRECT_URL || '' },
valkey: { url: env.VALKEY_URL || '', prefix: env.VALKEY_PREFIX || 'ov:wiki:' },
valkey: { url: env.VALKEY_URL || '', prefix: env.VALKEY_PREFIX || 'ov:wiki:' },
- // The SQLite file of releases before the switch: read once by scripts/migrate-to-postgres.js.
- dbPath: env.WIKI_DB_PATH || './data/wiki.db',
// Identity: OpenVibe.Network signs user JWTs (SSO) and service tokens (client credentials).
// Identity: OpenVibe.Network signs user JWTs (SSO) and service tokens (client credentials).
networkUrl,
networkUrl,
@@ -75,11 +75,10 @@ function createWikiService({ db, stores, outbox, config, community = null, vip =
@@ -75,11 +75,10 @@ function createWikiService({ db, stores, outbox, config, community = null, vip =
const access = createAccess(db, { vip });
const access = createAccess(db, { vip });
const origin = config.baseUrl;
const origin = config.baseUrl;
const policy = config.gate;
const policy = config.gate;
- // Every entry point reads the actor's roles again (one indexed query): a role granted a moment ago counts, as
- // it did when each check read SQLite.
+ // Every entry point reads the actor's roles again (one indexed query): a role granted a moment ago counts.
const roles = (actor, opts = { fresh: true }) => access.loadRoles(actor, opts);
const roles = (actor, opts = { fresh: true }) => access.loadRoles(actor, opts);
- // ── Queries (PostgreSQL; better-sqlite3-shaped async statements, openvibe-sdk/db prepare) ──
+ // ── Queries (PostgreSQL; async prepared statements via openvibe-sdk/db prepare) ──
const q = {
const q = {
spaceById: db.prepare('SELECT * FROM wiki_spaces WHERE id = ?'),
spaceById: db.prepare('SELECT * FROM wiki_spaces WHERE id = ?'),
spacesByIds: db.prepare('SELECT * FROM wiki_spaces WHERE id = ANY(?)'),
spacesByIds: db.prepare('SELECT * FROM wiki_spaces WHERE id = ANY(?)'),
@@ -134,7 +133,7 @@ function createWikiService({ db, stores, outbox, config, community = null, vip =
@@ -134,7 +133,7 @@ function createWikiService({ db, stores, outbox, config, community = null, vip =
insertOrigin: db.prepare(`INSERT INTO wiki_attachment_origins (attachment_id, page_id, media_id, attached_by, media_owner, media_visibility, attached_at)
insertOrigin: db.prepare(`INSERT INTO wiki_attachment_origins (attachment_id, page_id, media_id, attached_by, media_owner, media_visibility, attached_at)
VALUES (?, ?, ?, ?, ?, ?, ?)`),
VALUES (?, ?, ?, ?, ?, ?, ?)`),
originsOf: db.prepare('SELECT * FROM wiki_attachment_origins WHERE page_id = ?'),
originsOf: db.prepare('SELECT * FROM wiki_attachment_origins WHERE page_id = ?'),
- // Case-insensitive, as SQLite's LIKE was for ASCII.
+ // Case-insensitive title and content search.
search: db.prepare(`SELECT p.* FROM wiki_pages p JOIN wiki_spaces s ON s.id = p.space_id
search: db.prepare(`SELECT p.* FROM wiki_pages p JOIN wiki_spaces s ON s.id = p.space_id
JOIN wiki_page_revisions r ON r.entity_id = p.id AND r.number = p.published_revision
JOIN wiki_page_revisions r ON r.entity_id = p.id AND r.number = p.published_revision
WHERE p.state = 'published' AND s.deleted_at IS NULL AND (@space::text IS NULL OR s.slug = @space)
WHERE p.state = 'published' AND s.deleted_at IS NULL AND (@space::text IS NULL OR s.slug = @space)
@@ -4,9 +4,6 @@
@@ -4,9 +4,6 @@
* key, signed user JWTs and service tokens, and a stub fetch for the other services.
* key, signed user JWTs and service tokens, and a stub fetch for the other services.
*/
*/
const crypto = require('crypto');
const crypto = require('crypto');
-const fs = require('fs');
-const os = require('os');
-const path = require('path');
const { serviceAuth } = require('openvibe-contracts');
const { serviceAuth } = require('openvibe-contracts');
const { load } = require('../server/config');
const { load } = require('../server/config');
const { start } = require('../server/index');
const { start } = require('../server/index');
@@ -43,13 +40,11 @@ const quiet = process.env.WIKI_TEST_LOG ? console : { log() {}, warn() {}, error
@@ -43,13 +40,11 @@ const quiet = process.env.WIKI_TEST_LOG ? console : { log() {}, warn() {}, error
* A running Wiki on a database of its own (PGlite by default; WIKI_TEST_STORE=pg: the PostgreSQL + PgBouncer
* A running Wiki on a database of its own (PGlite by default; WIKI_TEST_STORE=pg: the PostgreSQL + PgBouncer
* containers). opts.db: boot on an existing handle (a restart keeps the data); h.stop() closes what boot opened.
* containers). opts.db: boot on an existing handle (a restart keeps the data); h.stop() closes what boot opened.
*/
*/
-async function boot({ env = {}, fetch: fetchImpl, dbPath, db: givenDb = null, now, workers = false, tokens, rateLimits = false, limitsNow = null, log = quiet } = {}) {
- const dir = dbPath ? path.dirname(dbPath) : fs.mkdtempSync(path.join(os.tmpdir(), 'wiki-test-'));
+async function boot({ env = {}, fetch: fetchImpl, db: givenDb = null, now, workers = false, tokens, rateLimits = false, limitsNow = null, log = quiet } = {}) {
const owned = givenDb ? null : await testDb();
const owned = givenDb ? null : await testDb();
const db = givenDb || owned.db;
const db = givenDb || owned.db;
const config = load({
const config = load({
NODE_ENV: 'test', PORT: '0', HOST: '127.0.0.1', BASE_URL: 'http://wiki.test',
NODE_ENV: 'test', PORT: '0', HOST: '127.0.0.1', BASE_URL: 'http://wiki.test',
- WIKI_DB_PATH: dbPath || path.join(dir, 'wiki.db'),
OV_NETWORK_URL: ISSUER, OV_NETWORK_INTERNAL_URL: '', WIKI_GATE_MIN_WORDS: '20',
OV_NETWORK_URL: ISSUER, OV_NETWORK_INTERNAL_URL: '', WIKI_GATE_MIN_WORDS: '20',
...env,
...env,
});
});
@@ -60,7 +55,7 @@ async function boot({ env = {}, fetch: fetchImpl, dbPath, db: givenDb = null, no
@@ -60,7 +55,7 @@ async function boot({ env = {}, fetch: fetchImpl, dbPath, db: givenDb = null, no
});
});
const base = `http://127.0.0.1:${h.server.address().port}`;
const base = `http://127.0.0.1:${h.server.address().port}`;
const stop = async ({ keepDb = false } = {}) => { await h.stop(); if (owned && !keepDb) await owned.close(); };
const stop = async ({ keepDb = false } = {}) => { await h.stop(); if (owned && !keepDb) await owned.close(); };
- return { ...h, stop, base, dir, dbPath: config.dbPath, closeDb: owned ? owned.close : async () => {} };
+ return { ...h, stop, base, closeDb: owned ? owned.close : async () => {} };
}
}
async function req(h, method, p, { token, body, form, headers = {}, cookie } = {}) {
async function req(h, method, p, { token, body, form, headers = {}, cookie } = {}) {
@@ -4,8 +4,6 @@
@@ -4,8 +4,6 @@
// measurement; raising one is a decision to state in the commit.
// measurement; raising one is a decision to state in the commit.
// node test/perf-budget.test.js
// node test/perf-budget.test.js
const assert = require('assert');
const assert = require('assert');
-const fs = require('fs');
-const os = require('os');
const net = require('net');
const net = require('net');
const path = require('path');
const path = require('path');
const { spawn } = require('child_process');
const { spawn } = require('child_process');
@@ -26,11 +24,10 @@ const BUDGETS = {
@@ -26,11 +24,10 @@ const BUDGETS = {
const freePort = () => new Promise((resolve) => { const s = net.createServer(); s.listen(0, '127.0.0.1', () => { const { port } = s.address(); s.close(() => resolve(port)); }); });
const freePort = () => new Promise((resolve) => { const s = net.createServer(); s.listen(0, '127.0.0.1', () => { const { port } = s.address(); s.close(() => resolve(port)); }); });
(async () => {
(async () => {
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ov-budget-'));
const port = await freePort();
const port = await freePort();
const child = spawn(process.execPath, [path.join(__dirname, '..', 'server', 'index.js')], {
const child = spawn(process.execPath, [path.join(__dirname, '..', 'server', 'index.js')], {
cwd: path.join(__dirname, '..'),
cwd: path.join(__dirname, '..'),
- env: { ...process.env, PORT: String(port), HOST: '127.0.0.1', NODE_ENV: 'test', WIKI_DB_PATH: path.join(dir, 'wiki.db') },
+ env: { ...process.env, PORT: String(port), HOST: '127.0.0.1', NODE_ENV: 'test' },
stdio: ['ignore', 'ignore', 'pipe'],
stdio: ['ignore', 'ignore', 'pipe'],
});
});
let stderr = '';
let stderr = '';
@@ -50,6 +47,5 @@ const freePort = () => new Promise((resolve) => { const s = net.createServer();
@@ -50,6 +47,5 @@ const freePort = () => new Promise((resolve) => { const s = net.createServer();
console.log('perf budget: all checks passed');
console.log('perf budget: all checks passed');
} finally {
} finally {
child.kill();
child.kill();
- fs.rmSync(dir, { recursive: true, force: true });
}
}
})().catch((err) => { console.error(err); process.exitCode = 1; });
})().catch((err) => { console.error(err); process.exitCode = 1; });
@@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
#!/usr/bin/env node
#!/usr/bin/env node
/**
/**
* Runs every test in test/ — the files named *.test.js — each in its own process, and fails if
* Runs every test in test/ — the files named *.test.js — each in its own process, and fails if
- * any of them fails. They use temp SQLite databases, a generated RSA key and stub upstreams; none
+ * any of them fails. They use temporary PGlite (PostgreSQL) databases, a generated RSA key and stub upstreams; none
* of them needs the network or a running OpenVibe service.
* of them needs the network or a running OpenVibe service.
*
*
* npm test # everything
* npm test # everything
@@ -14,7 +14,7 @@ const VIP_URL = 'http://127.0.0.1:4620/api/v1/policies/evaluate';
@@ -14,7 +14,7 @@ const VIP_URL = 'http://127.0.0.1:4620/api/v1/policies/evaluate';
(async () => {
(async () => {
// The schema: `vip` is a visibility PostgreSQL accepts, and anything else is still refused by the CHECK
// The schema: `vip` is a visibility PostgreSQL accepts, and anything else is still refused by the CHECK
- // (on SQLite a database made before `vip` was widened in place; migrations/0001 has it from the start).
+ // (migrations/0001 defines it from the start).
{
{
const { testDb } = require('./db-helper');
const { testDb } = require('./db-helper');
const { db, close } = await testDb();
const { db, close } = await testDb();