openvibers/openvibe.codes Commits
The SQLite era is gone (on PostgreSQL since 2026-09-28; no compatibility kept): the one-time migrate-to-postgres script, *_DB_PATH settings (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; its blockers (an edited applied migration, the lockfile) are resolved here, Host's inventory follow-up is separate. npm test 28/28 test files passed.
Changes
@@@ -6,14 +6,12 @@ HOST=127.0.0.1BASE_URL=https://openvibe.codesTRUST_PROXY=2# PostgreSQL (ADR-035), written by OpenVibe.Host roles/data/add-service.sh codes: the runtime role through PgBouncer,--# the owner on a direct connection (migrations and the one-time import), and Valkey (shared limit counters).++# 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.--CODES_DB_PATH=/var/lib/openvibe-codes/codes.db# Per-actor limits (server/http/actor-limits.js): reads one caller (an app, a person, else an address)# may make to the API and the portal per minute and per hour; past them 429 rate_limited with# Retry-After. Writes have their own numbers (README). The per-address limits stay.@@@ -8,7 +8,7 @@ jobs:test:uses: OpenVibers/OpenVibe.Shared/.github/workflows/test.yml@423fe519b5fe9594cc81b670e5ba5cb9f21f6176with:-- syntax-dirs: server public/js test scripts++ syntax-dirs: server public/js testcontracts-service: codes# ADR-035: PostgreSQL 18 + PgBouncer (transaction mode) + Valkey 9 containers (openvibe-sdk# scripts/test-services.sh). npm test runs every file on PGlite; test:pg runs them all through PgBouncer.@@@ -4,9 +4,6 @@ dist/.env.env.*!.env.example--*.db--*.db-wal--*.db-shm*.log*.pem*.key@@@ -75,7 +75,7 @@ For the playgrounds to succeed end to end (not Codes' code; configuration elsewh## Configuration--See [.env.example](.env.example). Required in production: `OV_OAUTH_CLIENT_SECRET`, `CODES_FORM_SECRET`, `BASE_URL`, `CODES_DB_PATH`. Optional: `EVENTS_URL` (relay), `CODES_STAFF_SUBJECTS`, `CODES_PLAYGROUND_*`, `CODES_REGISTRY_TTL_MS`, `CODES_LIMITS_MINUTE` / `CODES_LIMITS_HOUR`.++See [.env.example](.env.example). Required in production: `OV_OAUTH_CLIENT_SECRET`, `CODES_FORM_SECRET`, `BASE_URL`, `DATABASE_URL` (and `DATABASE_DIRECT_URL` for the boot migrations, run as the owner). Optional: `EVENTS_URL` (relay), `CODES_STAFF_SUBJECTS`, `CODES_PLAYGROUND_*`, `CODES_REGISTRY_TTL_MS`, `CODES_LIMITS_MINUTE` / `CODES_LIMITS_HOUR`.### Per-actor limits@@@ -113,10 +113,7 @@ Production deploys with `sudo ovhost deploy codes` on the host (strategy `git-chfast-forward `/opt/openvibe.codes`, install on a lockfile change, restart, wait for `/api/ready`).The unit is `openvibe-codes.service` on `127.0.0.1:4900`, the env file `/etc/openvibe/codes.env`. The database is`ov_codes` on the host's data role (`sudo /opt/openvibe.host/roles/data/add-service.sh codes` writes its settings); the--release migrates it at boot. The one-time move from SQLite is `scripts/migrate-to-postgres.js` (openvibe-sdk--`runSqliteMigration`, with a `--pglite` rehearsal mode), run while the service is stopped; the old--`/var/lib/openvibe-codes/codes.db` stays read-only for 7 days as the rollback. State lives in--`/var/lib/openvibe-codes`; nginx serves `openvibe.codes` from++release migrates it at boot. nginx serves `openvibe.codes` from[deploy/nginx/openvibe.codes.conf](deploy/nginx/openvibe.codes.conf).Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after therestart; afterwards `sudo ovhost rollback codes --to <sha>`. One blocker: the trust table was rebuilt@@@ -126,7 +123,7 @@ First install (done once; kept for a rebuild):1. `git clone` to `/opt/openvibe.codes`; `npm ci --omit=dev` with Node 22.2. `/etc/openvibe/codes.env` from `.env.example` (secrets from the Network client registration).--3. `deploy/systemd/openvibe-codes.service` → `/etc/systemd/system/`; `systemctl enable --now openvibe-codes`. State lives in `/var/lib/openvibe-codes`.++3. `deploy/systemd/openvibe-codes.service` → `/etc/systemd/system/`; `systemctl enable --now openvibe-codes`.4. `deploy/nginx/openvibe.codes.conf` → `/etc/nginx/sites-available/`, certificate for `openvibe.codes` + `www`, reload nginx.5. Check `curl -s http://127.0.0.1:4900/api/ready`.6. Only when the launch rule below holds: remove `openvibe.codes` from `OpenVibe.Sites/sites.json` and switch routing (done on 2026-09-23).@@@ -135,7 +132,7 @@ First install (done once; kept for a rebuild):```bashnpm install--fnm exec --using=22.22.1 npm test # every test/*.test.js on temp databases with mock Network, Events, Media++fnm exec --using=22.22.1 npm test # every test/*.test.js on temp PGlite databases with mock Network, Events, Mediafnm exec --using=22.22.1 npm run dev # http://localhost:4900npx openvibe-contracts-check --service codes --src server```@@@ -24,9 +24,7 @@ NoNewPrivileges=truePrivateTmp=trueProtectSystem=strictProtectHome=true--# Codes' own database lives in /var/lib/openvibe-codes; the code tree stays read-only.--StateDirectory=openvibe-codes--Environment=CODES_DB_PATH=/var/lib/openvibe-codes/codes.db++# Codes' own database is PostgreSQL on the host's data role; the code tree stays read-only.[Install]WantedBy=multi-user.target@@@ -9,7 +9,6 @@"version": "0.1.0","license": "AGPL-3.0-only","dependencies": {-- "better-sqlite3": "^11.10.0","busboy": "^1.6.0","cookie-parser": "^1.4.7","dotenv": "^16.4.7",@@@ -112,7 +111,9 @@"url": "https://feross.org/support"}],-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/better-sqlite3": {"version": "11.10.0",@@@ -120,6 +121,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"@@@ -130,6 +133,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"}@@@ -139,6 +144,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",@@@ -188,6 +195,8 @@}],"license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"base64-js": "^1.3.1","ieee754": "^1.1.13"@@@ -252,7 +261,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",@@@ -326,6 +337,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"},@@@ -341,6 +354,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"}@@@ -378,6 +393,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"}@@@ -437,6 +454,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"}@@@ -491,6 +510,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"}@@@ -582,7 +603,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",@@@ -624,7 +647,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",@@@ -676,7 +701,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",@@@ -776,7 +803,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",@@@ -788,7 +817,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",@@@ -1025,6 +1056,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"},@@@ -1037,6 +1070,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"}@@@ -1045,7 +1080,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",@@@ -1057,7 +1094,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",@@@ -1073,6 +1112,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"},@@@ -1109,6 +1150,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"}@@@ -1316,6 +1359,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",@@@ -1359,6 +1404,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"@@@ -1409,6 +1456,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",@@@ -1424,6 +1473,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",@@@ -1642,7 +1693,9 @@"url": "https://feross.org/support"}],-- "license": "MIT"++ "license": "MIT",++ "optional": true,++ "peer": true},"node_modules/simple-get": {"version": "4.0.1",@@@ -1663,6 +1716,8 @@}],"license": "MIT",++ "optional": true,++ "peer": true,"dependencies": {"decompress-response": "^6.0.0","once": "^1.3.1",@@@ -1706,6 +1761,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"}@@@ -1715,6 +1772,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"}@@@ -1724,6 +1783,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",@@@ -1736,6 +1797,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",@@@ -1761,6 +1824,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"},@@@ -1794,7 +1859,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",@@@ -1818,7 +1885,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",@@@ -21,7 +21,6 @@"license": "AGPL-3.0-only","repository": "github:OpenVibers/OpenVibe.Codes","dependencies": {-- "better-sqlite3": "^11.10.0","busboy": "^1.6.0","cookie-parser": "^1.4.7","dotenv": "^16.4.7",ddeleted file mode 100644@@@ -1,26 +0,0 @@--#!/usr/bin/env node--'use strict';--/**-- * The one-time move of Codes's SQLite database (CODES_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. Every table keeps its-- * name and columns.-- */--require('dotenv').config();--const { runSqliteMigration } = require('openvibe-sdk/db');--const configLib = require('../server/config');--const { MIGRATIONS } = require('../server/db');----const TABLES = {};----if (require.main === module) {-- const config = configLib.load();-- runSqliteMigration({ service: 'codes', 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 };@@@ -46,7 +46,7 @@ const PUBLIC_DIR = path.join(__dirname, '..', 'public');const VERSION = require('../package.json').version;/**-- * opts: config, store | dbPath, now (clock), fetchImpl, log, limitsNow (the per-actor limiter's clock,++ * opts: config, store, now (clock), fetchImpl, log, limitsNow (the per-actor limiter's clock,* tests), actorLimits (false: count nobody, tests only)*/async function createApp(opts = {}) {@@@ -43,8 +43,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:codes:' },-- // The SQLite file of releases before the switch: read once by scripts/migrate-to-postgres.js.-- dbPath: env.CODES_DB_PATH || './data/codes.db',// OpenVibe.Network: SSO (OAuth2 authorization server with PKCE), JWKS, the developer// projects API (/api/v1/projects, called server-side with the signed-in person's token),@@@ -10,7 +10,7 @@* could not manage as a member, or set a trust tier (ADR-022, for* Network's moderation audit log; subject { type: 'moderation_action' })*-- * emit() runs inside the SQLite transaction that makes the change, so an event exists if and only++ * emit() runs inside the PostgreSQL transaction that makes the change, so an event exists if and only* if its change committed. The relay publishes with Codes' OWN service token (events.event.publish,* audience openvibe.events) only when EVENTS_URL and OV_OAUTH_CLIENT_SECRET are set; otherwise rows* wait in event_outbox and /api/ready reports the relay as off. Payloads never carry a secret.@@@ -157,7 +157,7 @@ ${table(['Package', 'Version', 'License'], [[code(own.name || 'openvibe-codes'),index: true, cache: PUBLIC_CACHE, title: 'Transparency', crumbs: [{ label: 'Policy', href: '/policy' }, { label: 'Transparency' }],body: html`<h1>Transparency</h1><h2>What Codes stores</h2>--<p>Its own SQLite database has these tables and nothing else: ${TABLES.map((t, i) => html`${i ? ', ' : ''}<code>${t}</code>`)}, plus the event outbox. That is release metadata keyed to Network app ids, trust tiers (metadata), validated manifests, and a log of playground runs (who ran what, the outcome and the problem code).</p>++<p>Its own PostgreSQL database has these tables and nothing else: ${TABLES.map((t, i) => html`${i ? ', ' : ''}<code>${t}</code>`)}, plus the event outbox. That is release metadata keyed to Network app ids, trust tiers (metadata), validated manifests, and a log of playground runs (who ran what, the outcome and the problem code).</p><h2>What Codes does not store</h2><ul><li>Projects, members, apps, credentials, grants and quotas: OpenVibe.Network owns them; Codes shows what Network answers for the signed-in person.</li><li>Client secrets: Network returns a new secret once, Codes shows it in that response and keeps no copy. Network itself stores only a hash.</li>@@@ -2,7 +2,7 @@/*** Truthful readiness for GET /api/ready (openvibe-shared/ready, Track O).*-- * db required a real query on Codes' SQLite: every Codes table answers++ * db required a real query on Codes' PostgreSQL store: every Codes table answers* docs required the reference was generated at boot from the pinned packages* network_jwks optional the Network signing key is loaded; without it nobody can sign in and* app tokens cannot be verified (docs and tools still serve)@@@ -12,9 +12,6 @@ process.env.CODES_RATE_LIMIT_PER_MIN = process.env.CODES_RATE_LIMIT_PER_MIN || '* t.signIn(user) → cookie header value (codes_at = a Network user token, as after /auth/callback)* t.csrf(user), t.logs(), t.dbDump(), t.project(user, name), t.app(user, projectId, body)*/--const fs = require('fs');--const os = require('os');--const path = require('path');const http = require('http');const { startNetwork, startEvents, startMedia } = require('./mocks');@@@ -28,11 +25,8 @@ async function boot(opts = {}) {const network = await startNetwork(opts.network || {});const events = await startEvents(network);const media = await startMedia(network);-- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ov-codes-test-'));-- const dbPath = path.join(dir, 'codes.db');const env = {NODE_ENV: 'test', PORT: '0', BASE_URL: 'https://openvibe.codes', TRUST_PROXY: '1',-- CODES_DB_PATH: dbPath,OV_NETWORK_URL: network.url, OV_NETWORK_INTERNAL_URL: network.url,OV_OAUTH_CLIENT_ID: 'codes', OV_OAUTH_CLIENT_SECRET: 'codes-secret', COOKIE_SECURE: 'false',CODES_FORM_SECRET: 'test-form-secret',@@@ -114,14 +108,13 @@ async function boot(opts = {}) {}const t = {-- base, network, events, media, config, ctx: built.ctx, dbPath, get, signIn, csrf, dbDump, project, app, grant,++ base, network, events, media, config, ctx: built.ctx, get, signIn, csrf, dbDump, project, app, grant,logs: () => captured.join('\n'),async close() {await new Promise((r) => server.close(r));await built.ctx.outbox.stop();await testdb.close();await network.close(); await events.close(); await media.close();-- fs.rmSync(dir, { recursive: true, force: true });},};return t;@@@ -1,6 +1,6 @@#!/usr/bin/env node/**-- * Runs every test/*.test.js in its own process and fails if any fails. They use temp SQLite++ * Runs every test/*.test.js in its own process and fails if any fails. They use temp PGlite* databases and in-process mocks of OpenVibe.Network, Events and Media; none needs the* network or a running site.*
@@ -6,14 +6,12 @@ HOST=127.0.0.1
@@ -6,14 +6,12 @@ HOST=127.0.0.1
BASE_URL=https://openvibe.codes
BASE_URL=https://openvibe.codes
TRUST_PROXY=2
TRUST_PROXY=2
# PostgreSQL (ADR-035), written by OpenVibe.Host roles/data/add-service.sh codes: the runtime role through PgBouncer,
# PostgreSQL (ADR-035), written by OpenVibe.Host roles/data/add-service.sh codes: the runtime role through PgBouncer,
-# the owner on a direct connection (migrations and the one-time import), and Valkey (shared limit counters).
+# 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.
-CODES_DB_PATH=/var/lib/openvibe-codes/codes.db
# Per-actor limits (server/http/actor-limits.js): reads one caller (an app, a person, else an address)
# Per-actor limits (server/http/actor-limits.js): reads one caller (an app, a person, else an address)
# may make to the API and the portal per minute and per hour; past them 429 rate_limited with
# may make to the API and the portal per minute and per hour; past them 429 rate_limited with
# Retry-After. Writes have their own numbers (README). The per-address limits stay.
# Retry-After. Writes have their own numbers (README). The per-address limits stay.
@@ -8,7 +8,7 @@ jobs:
@@ -8,7 +8,7 @@ jobs:
test:
test:
uses: OpenVibers/OpenVibe.Shared/.github/workflows/test.yml@423fe519b5fe9594cc81b670e5ba5cb9f21f6176
uses: OpenVibers/OpenVibe.Shared/.github/workflows/test.yml@423fe519b5fe9594cc81b670e5ba5cb9f21f6176
with:
with:
- syntax-dirs: server public/js test scripts
+ syntax-dirs: server public/js test
contracts-service: codes
contracts-service: codes
# ADR-035: PostgreSQL 18 + PgBouncer (transaction mode) + Valkey 9 containers (openvibe-sdk
# ADR-035: PostgreSQL 18 + PgBouncer (transaction mode) + Valkey 9 containers (openvibe-sdk
# scripts/test-services.sh). npm test runs every file on PGlite; test:pg runs them all through PgBouncer.
# scripts/test-services.sh). npm test runs every file on PGlite; test:pg runs them all through PgBouncer.
@@ -4,9 +4,6 @@ dist/
@@ -4,9 +4,6 @@ dist/
.env
.env
.env.*
.env.*
!.env.example
!.env.example
-*.db
-*.db-wal
-*.db-shm
*.log
*.log
*.pem
*.pem
*.key
*.key
@@ -75,7 +75,7 @@ For the playgrounds to succeed end to end (not Codes' code; configuration elsewh
@@ -75,7 +75,7 @@ For the playgrounds to succeed end to end (not Codes' code; configuration elsewh
## Configuration
## Configuration
-See [.env.example](.env.example). Required in production: `OV_OAUTH_CLIENT_SECRET`, `CODES_FORM_SECRET`, `BASE_URL`, `CODES_DB_PATH`. Optional: `EVENTS_URL` (relay), `CODES_STAFF_SUBJECTS`, `CODES_PLAYGROUND_*`, `CODES_REGISTRY_TTL_MS`, `CODES_LIMITS_MINUTE` / `CODES_LIMITS_HOUR`.
+See [.env.example](.env.example). Required in production: `OV_OAUTH_CLIENT_SECRET`, `CODES_FORM_SECRET`, `BASE_URL`, `DATABASE_URL` (and `DATABASE_DIRECT_URL` for the boot migrations, run as the owner). Optional: `EVENTS_URL` (relay), `CODES_STAFF_SUBJECTS`, `CODES_PLAYGROUND_*`, `CODES_REGISTRY_TTL_MS`, `CODES_LIMITS_MINUTE` / `CODES_LIMITS_HOUR`.
### Per-actor limits
### Per-actor limits
@@ -113,10 +113,7 @@ Production deploys with `sudo ovhost deploy codes` on the host (strategy `git-ch
@@ -113,10 +113,7 @@ Production deploys with `sudo ovhost deploy codes` on the host (strategy `git-ch
fast-forward `/opt/openvibe.codes`, install on a lockfile change, restart, wait for `/api/ready`).
fast-forward `/opt/openvibe.codes`, install on a lockfile change, restart, wait for `/api/ready`).
The unit is `openvibe-codes.service` on `127.0.0.1:4900`, the env file `/etc/openvibe/codes.env`. The database is
The unit is `openvibe-codes.service` on `127.0.0.1:4900`, the env file `/etc/openvibe/codes.env`. The database is
`ov_codes` on the host's data role (`sudo /opt/openvibe.host/roles/data/add-service.sh codes` writes its settings); the
`ov_codes` on the host's data role (`sudo /opt/openvibe.host/roles/data/add-service.sh codes` writes its settings); the
-release migrates it at boot. The one-time move from SQLite is `scripts/migrate-to-postgres.js` (openvibe-sdk
-`runSqliteMigration`, with a `--pglite` rehearsal mode), run while the service is stopped; the old
-`/var/lib/openvibe-codes/codes.db` stays read-only for 7 days as the rollback. State lives in
-`/var/lib/openvibe-codes`; nginx serves `openvibe.codes` from
+release migrates it at boot. nginx serves `openvibe.codes` from
[deploy/nginx/openvibe.codes.conf](deploy/nginx/openvibe.codes.conf).
[deploy/nginx/openvibe.codes.conf](deploy/nginx/openvibe.codes.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 codes --to <sha>`. One blocker: the trust table was rebuilt
restart; afterwards `sudo ovhost rollback codes --to <sha>`. One blocker: the trust table was rebuilt
@@ -126,7 +123,7 @@ First install (done once; kept for a rebuild):
@@ -126,7 +123,7 @@ First install (done once; kept for a rebuild):
1. `git clone` to `/opt/openvibe.codes`; `npm ci --omit=dev` with Node 22.
1. `git clone` to `/opt/openvibe.codes`; `npm ci --omit=dev` with Node 22.
2. `/etc/openvibe/codes.env` from `.env.example` (secrets from the Network client registration).
2. `/etc/openvibe/codes.env` from `.env.example` (secrets from the Network client registration).
-3. `deploy/systemd/openvibe-codes.service` → `/etc/systemd/system/`; `systemctl enable --now openvibe-codes`. State lives in `/var/lib/openvibe-codes`.
+3. `deploy/systemd/openvibe-codes.service` → `/etc/systemd/system/`; `systemctl enable --now openvibe-codes`.
4. `deploy/nginx/openvibe.codes.conf` → `/etc/nginx/sites-available/`, certificate for `openvibe.codes` + `www`, reload nginx.
4. `deploy/nginx/openvibe.codes.conf` → `/etc/nginx/sites-available/`, certificate for `openvibe.codes` + `www`, reload nginx.
5. Check `curl -s http://127.0.0.1:4900/api/ready`.
5. Check `curl -s http://127.0.0.1:4900/api/ready`.
6. Only when the launch rule below holds: remove `openvibe.codes` from `OpenVibe.Sites/sites.json` and switch routing (done on 2026-09-23).
6. Only when the launch rule below holds: remove `openvibe.codes` from `OpenVibe.Sites/sites.json` and switch routing (done on 2026-09-23).
@@ -135,7 +132,7 @@ First install (done once; kept for a rebuild):
@@ -135,7 +132,7 @@ First install (done once; kept for a rebuild):
```bash
```bash
npm install
npm install
-fnm exec --using=22.22.1 npm test # every test/*.test.js on temp databases with mock Network, Events, Media
+fnm exec --using=22.22.1 npm test # every test/*.test.js on temp PGlite databases with mock Network, Events, Media
fnm exec --using=22.22.1 npm run dev # http://localhost:4900
fnm exec --using=22.22.1 npm run dev # http://localhost:4900
npx openvibe-contracts-check --service codes --src server
npx openvibe-contracts-check --service codes --src server
```
```
@@ -24,9 +24,7 @@ NoNewPrivileges=true
@@ -24,9 +24,7 @@ NoNewPrivileges=true
PrivateTmp=true
PrivateTmp=true
ProtectSystem=strict
ProtectSystem=strict
ProtectHome=true
ProtectHome=true
-# Codes' own database lives in /var/lib/openvibe-codes; the code tree stays read-only.
-StateDirectory=openvibe-codes
-Environment=CODES_DB_PATH=/var/lib/openvibe-codes/codes.db
+# Codes' own database is PostgreSQL on the host's data role; the code tree stays read-only.
[Install]
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target
@@ -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",
"busboy": "^1.6.0",
"busboy": "^1.6.0",
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
"dotenv": "^16.4.7",
"dotenv": "^16.4.7",
@@ -112,7 +111,9 @@
@@ -112,7 +111,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",
@@ -120,6 +121,8 @@
@@ -120,6 +121,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"
@@ -130,6 +133,8 @@
@@ -130,6 +133,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"
}
}
@@ -139,6 +144,8 @@
@@ -139,6 +144,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",
@@ -188,6 +195,8 @@
@@ -188,6 +195,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"
@@ -252,7 +261,9 @@
@@ -252,7 +261,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",
@@ -326,6 +337,8 @@
@@ -326,6 +337,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"
},
},
@@ -341,6 +354,8 @@
@@ -341,6 +354,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"
}
}
@@ -378,6 +393,8 @@
@@ -378,6 +393,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"
}
}
@@ -437,6 +454,8 @@
@@ -437,6 +454,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"
}
}
@@ -491,6 +510,8 @@
@@ -491,6 +510,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"
}
}
@@ -582,7 +603,9 @@
@@ -582,7 +603,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",
@@ -624,7 +647,9 @@
@@ -624,7 +647,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",
@@ -676,7 +701,9 @@
@@ -676,7 +701,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",
@@ -776,7 +803,9 @@
@@ -776,7 +803,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",
@@ -788,7 +817,9 @@
@@ -788,7 +817,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",
@@ -1025,6 +1056,8 @@
@@ -1025,6 +1056,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"
},
},
@@ -1037,6 +1070,8 @@
@@ -1037,6 +1070,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"
}
}
@@ -1045,7 +1080,9 @@
@@ -1045,7 +1080,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",
@@ -1057,7 +1094,9 @@
@@ -1057,7 +1094,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",
@@ -1073,6 +1112,8 @@
@@ -1073,6 +1112,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"
},
},
@@ -1109,6 +1150,8 @@
@@ -1109,6 +1150,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"
}
}
@@ -1316,6 +1359,8 @@
@@ -1316,6 +1359,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",
@@ -1359,6 +1404,8 @@
@@ -1359,6 +1404,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"
@@ -1409,6 +1456,8 @@
@@ -1409,6 +1456,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",
@@ -1424,6 +1473,8 @@
@@ -1424,6 +1473,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",
@@ -1642,7 +1693,9 @@
@@ -1642,7 +1693,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",
@@ -1663,6 +1716,8 @@
@@ -1663,6 +1716,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",
@@ -1706,6 +1761,8 @@
@@ -1706,6 +1761,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"
}
}
@@ -1715,6 +1772,8 @@
@@ -1715,6 +1772,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"
}
}
@@ -1724,6 +1783,8 @@
@@ -1724,6 +1783,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",
@@ -1736,6 +1797,8 @@
@@ -1736,6 +1797,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",
@@ -1761,6 +1824,8 @@
@@ -1761,6 +1824,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"
},
},
@@ -1794,7 +1859,9 @@
@@ -1794,7 +1859,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",
@@ -1818,7 +1885,9 @@
@@ -1818,7 +1885,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",
@@ -21,7 +21,6 @@
@@ -21,7 +21,6 @@
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"repository": "github:OpenVibers/OpenVibe.Codes",
"repository": "github:OpenVibers/OpenVibe.Codes",
"dependencies": {
"dependencies": {
- "better-sqlite3": "^11.10.0",
"busboy": "^1.6.0",
"busboy": "^1.6.0",
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
"dotenv": "^16.4.7",
"dotenv": "^16.4.7",
deleted file mode 100644
deleted file mode 100644
@@ -1,26 +0,0 @@
@@ -1,26 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-/**
- * The one-time move of Codes's SQLite database (CODES_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. Every table keeps its
- * name and columns.
- */
-require('dotenv').config();
-const { runSqliteMigration } = require('openvibe-sdk/db');
-const configLib = require('../server/config');
-const { MIGRATIONS } = require('../server/db');
-
-const TABLES = {};
-
-if (require.main === module) {
- const config = configLib.load();
- runSqliteMigration({ service: 'codes', 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 };
@@ -46,7 +46,7 @@ const PUBLIC_DIR = path.join(__dirname, '..', 'public');
@@ -46,7 +46,7 @@ const PUBLIC_DIR = path.join(__dirname, '..', 'public');
const VERSION = require('../package.json').version;
const VERSION = require('../package.json').version;
/**
/**
- * opts: config, store | dbPath, now (clock), fetchImpl, log, limitsNow (the per-actor limiter's clock,
+ * opts: config, store, now (clock), fetchImpl, log, limitsNow (the per-actor limiter's clock,
* tests), actorLimits (false: count nobody, tests only)
* tests), actorLimits (false: count nobody, tests only)
*/
*/
async function createApp(opts = {}) {
async function createApp(opts = {}) {
@@ -43,8 +43,6 @@ function load(env = process.env) {
@@ -43,8 +43,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:codes:' },
valkey: { url: env.VALKEY_URL || '', prefix: env.VALKEY_PREFIX || 'ov:codes:' },
- // The SQLite file of releases before the switch: read once by scripts/migrate-to-postgres.js.
- dbPath: env.CODES_DB_PATH || './data/codes.db',
// OpenVibe.Network: SSO (OAuth2 authorization server with PKCE), JWKS, the developer
// OpenVibe.Network: SSO (OAuth2 authorization server with PKCE), JWKS, the developer
// projects API (/api/v1/projects, called server-side with the signed-in person's token),
// projects API (/api/v1/projects, called server-side with the signed-in person's token),
@@ -10,7 +10,7 @@
@@ -10,7 +10,7 @@
* could not manage as a member, or set a trust tier (ADR-022, for
* could not manage as a member, or set a trust tier (ADR-022, for
* Network's moderation audit log; subject { type: 'moderation_action' })
* Network's moderation audit log; subject { type: 'moderation_action' })
*
*
- * emit() runs inside the SQLite transaction that makes the change, so an event exists if and only
+ * emit() runs inside the PostgreSQL transaction that makes the change, so an event exists if and only
* if its change committed. The relay publishes with Codes' OWN service token (events.event.publish,
* if its change committed. The relay publishes with Codes' OWN service token (events.event.publish,
* audience openvibe.events) only when EVENTS_URL and OV_OAUTH_CLIENT_SECRET are set; otherwise rows
* audience openvibe.events) only when EVENTS_URL and OV_OAUTH_CLIENT_SECRET are set; otherwise rows
* wait in event_outbox and /api/ready reports the relay as off. Payloads never carry a secret.
* wait in event_outbox and /api/ready reports the relay as off. Payloads never carry a secret.
@@ -157,7 +157,7 @@ ${table(['Package', 'Version', 'License'], [[code(own.name || 'openvibe-codes'),
@@ -157,7 +157,7 @@ ${table(['Package', 'Version', 'License'], [[code(own.name || 'openvibe-codes'),
index: true, cache: PUBLIC_CACHE, title: 'Transparency', crumbs: [{ label: 'Policy', href: '/policy' }, { label: 'Transparency' }],
index: true, cache: PUBLIC_CACHE, title: 'Transparency', crumbs: [{ label: 'Policy', href: '/policy' }, { label: 'Transparency' }],
body: html`<h1>Transparency</h1>
body: html`<h1>Transparency</h1>
<h2>What Codes stores</h2>
<h2>What Codes stores</h2>
-<p>Its own SQLite database has these tables and nothing else: ${TABLES.map((t, i) => html`${i ? ', ' : ''}<code>${t}</code>`)}, plus the event outbox. That is release metadata keyed to Network app ids, trust tiers (metadata), validated manifests, and a log of playground runs (who ran what, the outcome and the problem code).</p>
+<p>Its own PostgreSQL database has these tables and nothing else: ${TABLES.map((t, i) => html`${i ? ', ' : ''}<code>${t}</code>`)}, plus the event outbox. That is release metadata keyed to Network app ids, trust tiers (metadata), validated manifests, and a log of playground runs (who ran what, the outcome and the problem code).</p>
<h2>What Codes does not store</h2>
<h2>What Codes does not store</h2>
<ul><li>Projects, members, apps, credentials, grants and quotas: OpenVibe.Network owns them; Codes shows what Network answers for the signed-in person.</li>
<ul><li>Projects, members, apps, credentials, grants and quotas: OpenVibe.Network owns them; Codes shows what Network answers for the signed-in person.</li>
<li>Client secrets: Network returns a new secret once, Codes shows it in that response and keeps no copy. Network itself stores only a hash.</li>
<li>Client secrets: Network returns a new secret once, Codes shows it in that response and keeps no copy. Network itself stores only a hash.</li>
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
/**
/**
* Truthful readiness for GET /api/ready (openvibe-shared/ready, Track O).
* Truthful readiness for GET /api/ready (openvibe-shared/ready, Track O).
*
*
- * db required a real query on Codes' SQLite: every Codes table answers
+ * db required a real query on Codes' PostgreSQL store: every Codes table answers
* docs required the reference was generated at boot from the pinned packages
* docs required the reference was generated at boot from the pinned packages
* network_jwks optional the Network signing key is loaded; without it nobody can sign in and
* network_jwks optional the Network signing key is loaded; without it nobody can sign in and
* app tokens cannot be verified (docs and tools still serve)
* app tokens cannot be verified (docs and tools still serve)
@@ -12,9 +12,6 @@ process.env.CODES_RATE_LIMIT_PER_MIN = process.env.CODES_RATE_LIMIT_PER_MIN || '
@@ -12,9 +12,6 @@ process.env.CODES_RATE_LIMIT_PER_MIN = process.env.CODES_RATE_LIMIT_PER_MIN || '
* t.signIn(user) → cookie header value (codes_at = a Network user token, as after /auth/callback)
* t.signIn(user) → cookie header value (codes_at = a Network user token, as after /auth/callback)
* t.csrf(user), t.logs(), t.dbDump(), t.project(user, name), t.app(user, projectId, body)
* t.csrf(user), t.logs(), t.dbDump(), t.project(user, name), t.app(user, projectId, body)
*/
*/
-const fs = require('fs');
-const os = require('os');
-const path = require('path');
const http = require('http');
const http = require('http');
const { startNetwork, startEvents, startMedia } = require('./mocks');
const { startNetwork, startEvents, startMedia } = require('./mocks');
@@ -28,11 +25,8 @@ async function boot(opts = {}) {
@@ -28,11 +25,8 @@ async function boot(opts = {}) {
const network = await startNetwork(opts.network || {});
const network = await startNetwork(opts.network || {});
const events = await startEvents(network);
const events = await startEvents(network);
const media = await startMedia(network);
const media = await startMedia(network);
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ov-codes-test-'));
- const dbPath = path.join(dir, 'codes.db');
const env = {
const env = {
NODE_ENV: 'test', PORT: '0', BASE_URL: 'https://openvibe.codes', TRUST_PROXY: '1',
NODE_ENV: 'test', PORT: '0', BASE_URL: 'https://openvibe.codes', TRUST_PROXY: '1',
- CODES_DB_PATH: dbPath,
OV_NETWORK_URL: network.url, OV_NETWORK_INTERNAL_URL: network.url,
OV_NETWORK_URL: network.url, OV_NETWORK_INTERNAL_URL: network.url,
OV_OAUTH_CLIENT_ID: 'codes', OV_OAUTH_CLIENT_SECRET: 'codes-secret', COOKIE_SECURE: 'false',
OV_OAUTH_CLIENT_ID: 'codes', OV_OAUTH_CLIENT_SECRET: 'codes-secret', COOKIE_SECURE: 'false',
CODES_FORM_SECRET: 'test-form-secret',
CODES_FORM_SECRET: 'test-form-secret',
@@ -114,14 +108,13 @@ async function boot(opts = {}) {
@@ -114,14 +108,13 @@ async function boot(opts = {}) {
}
}
const t = {
const t = {
- base, network, events, media, config, ctx: built.ctx, dbPath, get, signIn, csrf, dbDump, project, app, grant,
+ base, network, events, media, config, ctx: built.ctx, get, signIn, csrf, dbDump, project, app, grant,
logs: () => captured.join('\n'),
logs: () => captured.join('\n'),
async close() {
async close() {
await new Promise((r) => server.close(r));
await new Promise((r) => server.close(r));
await built.ctx.outbox.stop();
await built.ctx.outbox.stop();
await testdb.close();
await testdb.close();
await network.close(); await events.close(); await media.close();
await network.close(); await events.close(); await media.close();
- fs.rmSync(dir, { recursive: true, force: true });
},
},
};
};
return t;
return t;
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
#!/usr/bin/env node
#!/usr/bin/env node
/**
/**
- * Runs every test/*.test.js in its own process and fails if any fails. They use temp SQLite
+ * Runs every test/*.test.js in its own process and fails if any fails. They use temp PGlite
* databases and in-process mocks of OpenVibe.Network, Events and Media; none needs the
* databases and in-process mocks of OpenVibe.Network, Events and Media; none needs the
* network or a running site.
* network or a running site.
*
*