feat: content fetch, sitemap fixes, remove oidcAuthFlow
- Add contentFetchFlow() to proxy (FR-001 through FR-012) - Add extractArticleBody() helper with vkm:articleBody / articleBody fallback - Dynamic proxyBaseUrl derivation from x-forwarded-proto/host headers - Forward query/size/category params on /sitemap.xml requests - Add Accept: application/ld+json header to content API calls - Remove oidcAuthFlow() - unmatched requests now return 404 Not Found - Fix xmlbuilder2 import: default import, call as xmlbuilder2.create(...) - Version bump 0.2.0 → 0.3.0 - 45/45 tests passing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -19,7 +19,7 @@ to `kme_CSA_settings.json` (`searchApiBaseUrl`, `tenant`, `proxyBaseUrl`).
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Node.js ≥18, ESM (`"type": "module"`)
|
||||
**Primary Dependencies**: `axios` (HTTP), `redis` (token cache), `xmlbuilder2` (XML — already injected as `xmlBuilder`), `uuid`, `jsonwebtoken` — all already in `package.json`
|
||||
**Primary Dependencies**: `axios` (HTTP), `redis` (token cache), `xmlbuilder2` (XML — already injected as `xmlbuilder2`), `uuid`, `jsonwebtoken` — all already in `package.json`
|
||||
**Storage**: Redis read/write (`hGet`/`hSet`) for OIDC token cache only — no new storage
|
||||
**Testing**: Node.js built-in test runner (`node:test`); no external test framework
|
||||
**Target Platform**: Linux server / container (HTTP proxy adapter)
|
||||
@@ -28,7 +28,7 @@ to `kme_CSA_settings.json` (`searchApiBaseUrl`, `tenant`, `proxyBaseUrl`).
|
||||
**Constraints**:
|
||||
- Zero `import`/`export` in `kmeContentSourceAdapter.js` (runs in `vm.createContext`)
|
||||
- No references to `config`, `global.config`, or `process.env` in proxy script
|
||||
- XML built exclusively with the injected `xmlBuilder` (FR-008)
|
||||
- XML built exclusively with the injected `xmlbuilder2` (FR-008)
|
||||
- No new npm packages; no new source files (monolithic architecture — Section I of constitution)
|
||||
**Scale/Scope**: Single tenant per deployment; all search results in one API call (no pagination, v1)
|
||||
|
||||
@@ -42,12 +42,12 @@ to `kme_CSA_settings.json` (`searchApiBaseUrl`, `tenant`, `proxyBaseUrl`).
|
||||
|---|---|---|---|
|
||||
| I | Monolithic architecture | ✅ PASS | All new code added to `kmeContentSourceAdapter.js`; no new source files |
|
||||
| I (vm.Script) | Zero imports/exports in proxy script | ✅ PASS | Sitemap logic is inlined; no import statements introduced |
|
||||
| I.0 | No forbidden globals (`config`, `global.config`, `process.env`) | ✅ PASS | Only `kme_CSA_settings`, `redis`, `axios`, `xmlBuilder`, `req`, `res` used |
|
||||
| I.0 | No forbidden globals (`config`, `global.config`, `process.env`) | ✅ PASS | Only `kme_CSA_settings`, `redis`, `axios`, `xmlbuilder2`, `req`, `res` used |
|
||||
| I.I | Business logic in proxy.js | ✅ PASS | Auth, API call, XML generation all in `kmeContentSourceAdapter.js` |
|
||||
| I.II | Separate files only for allowed categories | ✅ PASS | Settings JSON in `src/globalVariables/` (existing pattern) |
|
||||
| I.III | No new files challenged | ✅ PASS | No new files in `src/` |
|
||||
| I.IV | New config in `src/globalVariables/` not `config/default.json` | ✅ PASS | Three fields added to `kme_CSA_settings.json` |
|
||||
| I.V | `xmlBuilder` already in `globalVMContext` | ✅ PASS | `xmlbuilder2` `create` already injected; no server.js changes needed |
|
||||
| I.V | `xmlbuilder2` already in `globalVMContext` | ✅ PASS | `xmlbuilder2` `create` already injected; no server.js changes needed |
|
||||
| II | API-First Design | ✅ PASS | HTTP contract documented in `contracts/sitemap-endpoint.md` |
|
||||
| III | Test-First Development | ✅ REQUIRED | Unit + contract tests must be written before/alongside implementation |
|
||||
| VII | No new dependencies | ✅ PASS | All required packages already installed (`xmlbuilder2`, `axios`, `redis`) |
|
||||
@@ -103,7 +103,7 @@ settings JSON, and the existing test files are modified.
|
||||
|---|---|---|
|
||||
| R-001 | Token reuse | Inline shared `getValidToken()` helper in proxy script; branch on URL first |
|
||||
| R-002 | Search API response shape | Assume `{ items: [...] }`; verify against live API during implementation |
|
||||
| R-003 | xmlbuilder2 API | `xmlBuilder({...}).ele('urlset',{xmlns:...})…doc.end({})` — no prettyPrint |
|
||||
| R-003 | xmlbuilder2 API | `xmlbuilder2({...}).ele('urlset',{xmlns:...})…doc.end({})` — no prettyPrint |
|
||||
| R-004 | Error mapping | Reuse `err.response` / `err.code === ECONNABORTED\|ERR_CANCELED` pattern |
|
||||
| R-005 | Settings validation | `requiredSitemapFields` guard before any async work → HTTP 500 |
|
||||
| R-006 | `loc` construction | `` `${proxyBaseUrl}?kmeURL=${encodeURIComponent(item['vkm:url'])}` `` |
|
||||
@@ -183,7 +183,7 @@ async function sitemapFlow() {
|
||||
const items = searchResponse.data.items ?? searchResponse.data ?? [];
|
||||
|
||||
// FR-004, FR-005, FR-006, FR-008: Build sitemap XML
|
||||
const doc = xmlBuilder({ version: '1.0', encoding: 'UTF-8' });
|
||||
const doc = xmlbuilder2({ version: '1.0', encoding: 'UTF-8' });
|
||||
const urlset = doc.ele('urlset', { xmlns: 'http://www.sitemaps.org/schemas/sitemap/0.9' });
|
||||
for (const item of items) {
|
||||
const vkmUrl = item['vkm:url'];
|
||||
|
||||
Reference in New Issue
Block a user