# Agentscript.org/examples reverse-proxy and cache ## 1\. Goals - Provide **clean URLs** like `https://agentscript.org/examples/...` instead of raw GitHub URLs. - Keep the **example models library** (from GitHub `backspaces/agentscript`) editable on GitHub using existing workflow for Owen - Allow **users to copy/fork** examples into their personal workspace (`https://agentscript.org/users/Alice/...`) for editing and saving. - Integrate a **reverse proxy + cache** so examples are always up-to-date and quick to load. ## 2\. Mapping Strategy - **Reverse Proxy**: - All requests for `agentscript.org/examples/*` to Nephele on node map to: ``` https://raw.githubusercontent.com/backspaces/agentscript/master/* ``` Example: `https://agentscript.org/examples/viewes2/ants/index.html` → `https://raw.githubusercontent.com/backspaces/agentscript/master/views2/ants/index.html` - Achieved in Nephele via a Node.js middleware module (`reverseProxy.js`). - **Cache Layer**: - Before proxying to GitHub, the server checks a local cache: - If found, return immediately. - If not found, fetch from GitHub, store in cache, return to client. - Cache can be in-memory or filesystem-based with a TTL (e.g., 1 hour) to minimize GitHub rate limits. ## 3\. User Forking via WebDAV - **WebDAV `COPY`** is used to duplicate files from `/examples` into a user’s namespace: ``` COPY https://agentscript.org/examples/views2d/ants/index.html → https://agentscript.org/users/Alice/views2d/ants/index.html ``` - The source is served by the reverse proxy (cache-backed), and the destination is saved locally in the `/users/Alice` directory. - Once copied, **Alice’s workspace is independent**—edits do not affect the shared examples. ## 4\. Why Reverse Proxy Instead of Sync? - Avoids maintaining a separate `git pull` workflow on the server. - Always serves the latest GitHub master branch. - With caching, performance is close to local hosting. ## 5\. Implementation Notes - **reverseProxy.js** handles mapping from `/examples/*` to the GitHub raw URL. - **cache.js** module wraps the proxy with a fast in-memory or disk-based cache. - Nephele `server.js` acts like an `httpd.conf`, where routes like `/examples/*` are registered to `reverseProxy.js`. - WebDAV operations for `COPY` (or `MOVE`) operate transparently, since they just read the proxied content. ## 6\. Future Enhancements - **Hybrid fallback:** Serve files from a local mirror if GitHub is unavailable. - **Version pinning:** Optionally point `/examples` to tagged versions of the GitHub repo. * * * # Reverse Proxy + Cache Code ## cache.js ```js const cache = new Map(); const TTL = 60 * 1000; // 1 minute TTL function set(key, value) { cache.set(key, { value, expires: Date.now() + TTL }); } function get(key) { const entry = cache.get(key); if (!entry || Date.now() > entry.expires) { cache.delete(key); return null; } return entry.value; } module.exports = { get, set }; ``` ## reverseProxyWithCache.js ```js const httpProxy = require('http-proxy'); const { get, set } = require('./cache'); const proxy = httpProxy.createProxyServer({ changeOrigin: true }); module.exports = function reverseProxyWithCache(req, res) { const githubPath = req.url.replace(/^\/examples\//, ''); const cacheKey = `examples:${githubPath}`; // 1. Check cache const cached = get(cacheKey); if (cached) { res.writeHead(200, { 'Content-Type': cached.contentType }); res.end(cached.body); return; } // 2. Proxy & capture response proxy.web(req, res, { target: `https://raw.githubusercontent.com/backspaces/agentscript/master/${githubPath}` }); proxy.on('proxyRes', (proxyRes, req, res) => { let body = []; proxyRes.on('data', chunk => body.push(chunk)); proxyRes.on('end', () => { const buffer = Buffer.concat(body); set(cacheKey, { contentType: proxyRes.headers['content-type'], body: buffer }); }); }); }; ``` ## server.js (Nephele Integration) ```js const nephele = require('nephele'); const reverseProxyWithCache = require('./reverseProxyWithCache'); const server = nephele({ root: './public', port: 8080 }); server.route('/examples/*', reverseProxyWithCache); server.listen(); ```