openvibers/openvibe.wiki Commits
Keep Wiki up when INDEXNOWKEY is invalid and warn instead
Changes
@@@ -3,3 +3,4 @@## Unreleased- Every page is rendered through `openvibe-publishing/layout` (`openvibe-shared/shell` page()) instead of a local template: the same head tags, stylesheets, feed links, app icon and Frame, with robots still explicit on every page (the gate's decision on an article, a string elsewhere); `openvibe-shared` v2.5.0 → v2.6.0 and `openvibe-publishing` v1.1.0 → v1.2.0, and the JS size budgets rise by the shell's `web-runtime.js` (5 files, 245 KB raw, 59 KB brotli).++- A set-but-invalid `INDEXNOW_KEY` (not 8–128 hex/alnum) no longer crashes the service at boot: Wiki logs a warning and serves with IndexNow off, exactly as when the key is unset.@@@ -132,7 +132,8 @@ records who attached each Media object and what Media said about it at that momeunpublishing and deleting a public, indexable page pings `api.indexnow.org` with the page'scanonical URL and `/sitemap.xml` (the module batches and debounces; a failed ping never takes apublish down). Drafts, private, members, VIP and noindex pages never ping. Unset: off — no key-- file, no requests.++ file, no requests. A key that is not 8–128 hex or alphanumeric is refused by the module: Wiki++ warns and runs with IndexNow off rather than failing to start.- **The gate**: `openvibe-publishing/seo` decides indexing per page with explicit reasons(policy: at least `WIKI_GATE_MIN_WORDS` words and `WIKI_GATE_MIN_SOURCES` citations; AI text andAI-assisted imports only after a person's review; owner-requested noindex). Only public, published, indexable pages enter sitemaps and@@@ -49,7 +49,18 @@ async function start({ config, db: givenDb = null, now = () => Date.now(), fetch// IndexNow (openvibe-shared/indexnow): created once at boot from INDEXNOW_KEY. Unset → off, nothing// mounted and nothing sent; a test or a drill injects its own (a spy, or the module's own no-key// state) through `indexnow`, and the outbound POST goes through `fetchImpl`, this process's stub.-- const indexnow = givenIndexNow || createIndexNow({ host: config.baseUrl, key: config.indexnow.key, fetch: fetchImpl, log: (...a) => (log.warn || console.warn)(...a) });++ // A set-but-invalid key (the module refuses anything but 8–128 hex/alnum) is a configuration++ // mistake, not a reason to leave the wiki down: warn and run with IndexNow off, exactly as unset.++ let indexnow = givenIndexNow;++ if (!indexnow) {++ const logIndexNow = (...a) => (log.warn || console.warn)(...a);++ try {++ indexnow = createIndexNow({ host: config.baseUrl, key: config.indexnow.key, fetch: fetchImpl, log: logIndexNow });++ } catch (err) {++ logIndexNow(`[Wiki] ${err.message} — IndexNow is off until INDEXNOW_KEY is fixed`);++ indexnow = createIndexNow({ host: config.baseUrl, key: '', fetch: fetchImpl, log: logIndexNow });++ }++ }// Valkey (ADR-035): shared, never-authoritative state (per-actor limit counters). Optional.const valkey = config.valkey.url ? require('openvibe-sdk/valkey').createValkey({ url: config.valkey.url, prefix: config.valkey.prefix, log }) : null;const platform = createPlatform({ config, db, fetchImpl, tokens, now, log });@@@ -21,6 +21,17 @@ const PAGE = `${BASE}/w/notes/first-light`;assert.strictEqual((await H.req(off, 'GET', `/${KEY}.txt`)).status, 404, 'no key file is served');} finally { await off.stop(); }++ // A set-but-invalid key is a configuration mistake, not a boot failure: the wiki serves, IndexNow++ // is off, and the mistake is warned about (createIndexNow refuses anything but 8–128 hex/alnum).++ const warnings = [];++ const badLog = { log() {}, warn: (m) => warnings.push(String(m)), error() {} };++ const bad = await H.boot({ env: { BASE_URL: BASE, INDEXNOW_KEY: 'not a key!' }, log: badLog });++ try {++ assert.strictEqual(bad.indexnow.enabled, false, 'an invalid key leaves IndexNow off');++ assert.ok(warnings.some((w) => w.includes('INDEXNOW_KEY')), `the bad key is warned about: ${JSON.stringify(warnings)}`);++ assert.strictEqual((await H.req(bad, 'GET', `/${KEY}.txt`)).status, 404, 'no key file is served for an invalid key');++ } finally { await bad.stop(); }++// With a key: the key file is served as text/plain with the key.const on = await H.boot({ env: { BASE_URL: BASE, INDEXNOW_KEY: KEY } });try {
@@ -3,3 +3,4 @@
@@ -3,3 +3,4 @@
## Unreleased
## Unreleased
- Every page is rendered through `openvibe-publishing/layout` (`openvibe-shared/shell` page()) instead of a local template: the same head tags, stylesheets, feed links, app icon and Frame, with robots still explicit on every page (the gate's decision on an article, a string elsewhere); `openvibe-shared` v2.5.0 → v2.6.0 and `openvibe-publishing` v1.1.0 → v1.2.0, and the JS size budgets rise by the shell's `web-runtime.js` (5 files, 245 KB raw, 59 KB brotli).
- Every page is rendered through `openvibe-publishing/layout` (`openvibe-shared/shell` page()) instead of a local template: the same head tags, stylesheets, feed links, app icon and Frame, with robots still explicit on every page (the gate's decision on an article, a string elsewhere); `openvibe-shared` v2.5.0 → v2.6.0 and `openvibe-publishing` v1.1.0 → v1.2.0, and the JS size budgets rise by the shell's `web-runtime.js` (5 files, 245 KB raw, 59 KB brotli).
+- A set-but-invalid `INDEXNOW_KEY` (not 8–128 hex/alnum) no longer crashes the service at boot: Wiki logs a warning and serves with IndexNow off, exactly as when the key is unset.
@@ -132,7 +132,8 @@ records who attached each Media object and what Media said about it at that mome
@@ -132,7 +132,8 @@ records who attached each Media object and what Media said about it at that mome
unpublishing and deleting a public, indexable page pings `api.indexnow.org` with the page's
unpublishing and deleting a public, indexable page pings `api.indexnow.org` with the page's
canonical URL and `/sitemap.xml` (the module batches and debounces; a failed ping never takes a
canonical URL and `/sitemap.xml` (the module batches and debounces; a failed ping never takes a
publish down). Drafts, private, members, VIP and noindex pages never ping. Unset: off — no key
publish down). Drafts, private, members, VIP and noindex pages never ping. Unset: off — no key
- file, no requests.
+ file, no requests. A key that is not 8–128 hex or alphanumeric is refused by the module: Wiki
+ warns and runs with IndexNow off rather than failing to start.
- **The gate**: `openvibe-publishing/seo` decides indexing per page with explicit reasons
- **The gate**: `openvibe-publishing/seo` decides indexing per page with explicit reasons
(policy: at least `WIKI_GATE_MIN_WORDS` words and `WIKI_GATE_MIN_SOURCES` citations; AI text and
(policy: at least `WIKI_GATE_MIN_WORDS` words and `WIKI_GATE_MIN_SOURCES` citations; AI text and
AI-assisted imports only after a person's review; owner-requested noindex). Only public, published, indexable pages enter sitemaps and
AI-assisted imports only after a person's review; owner-requested noindex). Only public, published, indexable pages enter sitemaps and
@@ -49,7 +49,18 @@ async function start({ config, db: givenDb = null, now = () => Date.now(), fetch
@@ -49,7 +49,18 @@ async function start({ config, db: givenDb = null, now = () => Date.now(), fetch
// IndexNow (openvibe-shared/indexnow): created once at boot from INDEXNOW_KEY. Unset → off, nothing
// IndexNow (openvibe-shared/indexnow): created once at boot from INDEXNOW_KEY. Unset → off, nothing
// mounted and nothing sent; a test or a drill injects its own (a spy, or the module's own no-key
// mounted and nothing sent; a test or a drill injects its own (a spy, or the module's own no-key
// state) through `indexnow`, and the outbound POST goes through `fetchImpl`, this process's stub.
// state) through `indexnow`, and the outbound POST goes through `fetchImpl`, this process's stub.
- const indexnow = givenIndexNow || createIndexNow({ host: config.baseUrl, key: config.indexnow.key, fetch: fetchImpl, log: (...a) => (log.warn || console.warn)(...a) });
+ // A set-but-invalid key (the module refuses anything but 8–128 hex/alnum) is a configuration
+ // mistake, not a reason to leave the wiki down: warn and run with IndexNow off, exactly as unset.
+ let indexnow = givenIndexNow;
+ if (!indexnow) {
+ const logIndexNow = (...a) => (log.warn || console.warn)(...a);
+ try {
+ indexnow = createIndexNow({ host: config.baseUrl, key: config.indexnow.key, fetch: fetchImpl, log: logIndexNow });
+ } catch (err) {
+ logIndexNow(`[Wiki] ${err.message} — IndexNow is off until INDEXNOW_KEY is fixed`);
+ indexnow = createIndexNow({ host: config.baseUrl, key: '', fetch: fetchImpl, log: logIndexNow });
+ }
+ }
// Valkey (ADR-035): shared, never-authoritative state (per-actor limit counters). Optional.
// Valkey (ADR-035): shared, never-authoritative state (per-actor limit counters). Optional.
const valkey = config.valkey.url ? require('openvibe-sdk/valkey').createValkey({ url: config.valkey.url, prefix: config.valkey.prefix, log }) : null;
const valkey = config.valkey.url ? require('openvibe-sdk/valkey').createValkey({ url: config.valkey.url, prefix: config.valkey.prefix, log }) : null;
const platform = createPlatform({ config, db, fetchImpl, tokens, now, log });
const platform = createPlatform({ config, db, fetchImpl, tokens, now, log });
@@ -21,6 +21,17 @@ const PAGE = `${BASE}/w/notes/first-light`;
@@ -21,6 +21,17 @@ const PAGE = `${BASE}/w/notes/first-light`;
assert.strictEqual((await H.req(off, 'GET', `/${KEY}.txt`)).status, 404, 'no key file is served');
assert.strictEqual((await H.req(off, 'GET', `/${KEY}.txt`)).status, 404, 'no key file is served');
} finally { await off.stop(); }
} finally { await off.stop(); }
+ // A set-but-invalid key is a configuration mistake, not a boot failure: the wiki serves, IndexNow
+ // is off, and the mistake is warned about (createIndexNow refuses anything but 8–128 hex/alnum).
+ const warnings = [];
+ const badLog = { log() {}, warn: (m) => warnings.push(String(m)), error() {} };
+ const bad = await H.boot({ env: { BASE_URL: BASE, INDEXNOW_KEY: 'not a key!' }, log: badLog });
+ try {
+ assert.strictEqual(bad.indexnow.enabled, false, 'an invalid key leaves IndexNow off');
+ assert.ok(warnings.some((w) => w.includes('INDEXNOW_KEY')), `the bad key is warned about: ${JSON.stringify(warnings)}`);
+ assert.strictEqual((await H.req(bad, 'GET', `/${KEY}.txt`)).status, 404, 'no key file is served for an invalid key');
+ } finally { await bad.stop(); }
+
// With a key: the key file is served as text/plain with the key.
// With a key: the key file is served as text/plain with the key.
const on = await H.boot({ env: { BASE_URL: BASE, INDEXNOW_KEY: KEY } });
const on = await H.boot({ env: { BASE_URL: BASE, INDEXNOW_KEY: KEY } });
try {
try {