Skip to content

Add dynamic sitemap and plugin map endpoints#28

Closed
023dominus-coder wants to merge 1 commit into
ubiquity:mainfrom
023dominus-coder:bounty-2-dynamic-sitemap
Closed

Add dynamic sitemap and plugin map endpoints#28
023dominus-coder wants to merge 1 commit into
ubiquity:mainfrom
023dominus-coder:bounty-2-dynamic-sitemap

Conversation

@023dominus-coder

Copy link
Copy Markdown

Closes #2

Summary

Adds deterministic sitemap and plugin map generation for UBQ.FI apps and plugins.

What changed

  • Added src/sitemap.ts with JSON sitemap, plugin map, and XML rendering helpers.
  • Added Worker endpoints: /sitemap.xml, /sitemap.json, and /plugins.json.
  • Added tests covering app/plugin entries, XML rendering, JSON structures, and Worker routing before proxy fallback.

Notes

The implementation is local-config driven and keeps the router's no-KV/no-discovery approach.

Validation

Could not run bun test locally because bun, npm, and tsc are not available on PATH in this environment.

@ubiquity-os

ubiquity-os Bot commented May 30, 2026

Copy link
Copy Markdown

Warning

@023dominus-coder this pull request is linked to an issue that is already assigned to another user. Please link it to an open issue assigned to you or to an unassigned open issue.

@ubiquity-os ubiquity-os Bot closed this May 30, 2026
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a standalone sitemap generator for apps and plugins. It adds type contracts for sitemap metadata (apps, plugins, entries), builder functions to generate sorted sitemap entries and JSON payloads from defaults, an XML renderer with escape handling, and helper converters for app/plugin-to-entry transformation. The worker router is extended with three deterministic endpoints—/sitemap.xml, /sitemap.json, and /plugins.json—that serve generated sitemaps with appropriate content types and cache headers. A test suite verifies entry generation, XML/JSON formatting, payload structure, and worker endpoint responses.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: adding sitemap and plugin map endpoints to the worker.
Description check ✅ Passed Description directly relates to the changeset, detailing new files, endpoints, and tests added.
Linked Issues check ✅ Passed PR fully implements issue #2 requirements: generates XML/JSON sitemaps and plugin maps reflecting all apps and plugins.
Out of Scope Changes check ✅ Passed All changes are scoped to sitemap/plugin map generation; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 897890bd-0c5d-4af4-84c4-1827371ebec2

📥 Commits

Reviewing files that changed from the base of the PR and between 91bebfb and 629c2e3.

📒 Files selected for processing (3)
  • src/sitemap.ts
  • src/worker.ts
  • tests/sitemap.test.ts

Comment thread src/worker.ts
Comment on lines +82 to +97
if (url.pathname === '/sitemap.xml') {
return withRouterRevision(new Response(renderSitemapXml(), {
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, max-age=300',
},
}))
}

if (url.pathname === '/sitemap.json') {
return withRouterRevision(json(buildJsonSitemap()))
}

if (url.pathname === '/plugins.json') {
return withRouterRevision(json(buildJsonPluginMap()))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Look for existing host/apex gating patterns and any app-level sitemap handling in the router.
rg -nP "url\.hostname|inHost\s*===|=== '?ubq\.fi" --type=ts
rg -nP "sitemap|plugins\.json" --type=ts -g '!tests/**'

Repository: ubiquity/ubq.fi-router

Length of output: 665


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant section of src/worker.ts around sitemap endpoints and any surrounding host gating.
sed -n '60,120p' src/worker.ts

# Find where 'pathname' routing branches are defined and whether hostname/inHost gating is applied for them.
rg -n "pathname === '/(sitemap\.xml|sitemap\.json|plugins\.json)'" src/worker.ts
rg -n "inHost\s*=" src/worker.ts
rg -n "workIncoming:|=== 'work\.ubq\.fi'" src/worker.ts

# Inspect the router helper to see whether it already scopes by hostname.
rg -n "function withRouterRevision|withRouterRevision" -S src
ls -la src | head

Repository: ubiquity/ubq.fi-router

Length of output: 3792


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "/sitemap\.xml|sitemap\.json|plugins\.json" -S src
rg -n "buildJsonSitemap|renderSitemapXml|buildJsonPluginMap" -S src/sitemap.ts src/worker.ts
rg -n "hostname|inHost|apex|ubq\.fi" -S src/sitemap.ts src/worker.ts

Repository: ubiquity/ubq.fi-router

Length of output: 2243


Scope sitemap/plugin JSON routes by hostname (avoid shadowing proxied apps)

In src/worker.ts, /sitemap.xml, /sitemap.json, and /plugins.json are matched on url.pathname only, and run before any url.hostname/plugin routing logic—so these endpoints are served for all incoming hosts. If a proxied app serves its own sitemap at these paths, this router will shadow it; gate these routes to intended apex/allowed hostnames (e.g., ubq.fi / www.ubq.fi).

Comment thread tests/sitemap.test.ts
Comment on lines +38 to +47
test('serves sitemap and plugin map endpoints before proxy routing', async () => {
const xml = await worker.fetch(new Request('https://ubq.fi/sitemap.xml'), {} as Env)
const json = await worker.fetch(new Request('https://ubq.fi/sitemap.json'), {} as Env)
const plugins = await worker.fetch(new Request('https://ubq.fi/plugins.json'), {} as Env)

expect(xml.headers.get('content-type')).toContain('application/xml')
expect(await xml.text()).toContain('<urlset')
expect((await json.json()).total).toBeGreaterThan(0)
expect((await plugins.json()).totalPlugins).toBeGreaterThan(0)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix the failing tsc build: .json() resolves to unknown.

CI is red at Lines 45-46 (TS2571). Response.json() returns unknown, so property access fails type-checking. Cast the parsed payloads.

🐛 Proposed fix
-    expect((await json.json()).total).toBeGreaterThan(0)
-    expect((await plugins.json()).totalPlugins).toBeGreaterThan(0)
+    expect(((await json.json()) as { total: number }).total).toBeGreaterThan(0)
+    expect(((await plugins.json()) as { totalPlugins: number }).totalPlugins).toBeGreaterThan(0)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('serves sitemap and plugin map endpoints before proxy routing', async () => {
const xml = await worker.fetch(new Request('https://ubq.fi/sitemap.xml'), {} as Env)
const json = await worker.fetch(new Request('https://ubq.fi/sitemap.json'), {} as Env)
const plugins = await worker.fetch(new Request('https://ubq.fi/plugins.json'), {} as Env)
expect(xml.headers.get('content-type')).toContain('application/xml')
expect(await xml.text()).toContain('<urlset')
expect((await json.json()).total).toBeGreaterThan(0)
expect((await plugins.json()).totalPlugins).toBeGreaterThan(0)
})
test('serves sitemap and plugin map endpoints before proxy routing', async () => {
const xml = await worker.fetch(new Request('https://ubq.fi/sitemap.xml'), {} as Env)
const json = await worker.fetch(new Request('https://ubq.fi/sitemap.json'), {} as Env)
const plugins = await worker.fetch(new Request('https://ubq.fi/plugins.json'), {} as Env)
expect(xml.headers.get('content-type')).toContain('application/xml')
expect(await xml.text()).toContain('<urlset')
expect(((await json.json()) as { total: number }).total).toBeGreaterThan(0)
expect(((await plugins.json()) as { totalPlugins: number }).totalPlugins).toBeGreaterThan(0)
})
🧰 Tools
🪛 GitHub Actions: CI / 2_test.txt

[error] 45-45: TypeScript (tsc) error TS2571: Object is of type 'unknown'.


[error] 46-46: TypeScript (tsc) error TS2571: Object is of type 'unknown'.

🪛 GitHub Actions: CI / test

[error] 45-45: TypeScript (tsc): TS2571 Object is of type 'unknown'.


[error] 46-46: TypeScript (tsc): TS2571 Object is of type 'unknown'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dynamic Sitemap (Apps & Plugins)

1 participant