@pleri/olam-cli 0.1.41 → 0.1.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "auth": "sha256:4e2ea22c5ef026ecf7b10892fbe381384b32e83636962d86d9ab1fc572972f8e",
3
3
  "devbox": "sha256:9363a1979d7df0ed2b2c964c183ba3e739383c146416f27b1ceb976f64648fd9",
4
- "host-cp": "sha256:7687f465665a0a946cd1c16bbc5c384011bd68df752cab2c19e8f4deb2b263cb",
4
+ "host-cp": "sha256:29d2e544db7fabae259a0311a76ff367ee5e2ca5f48e9640ebefaf3c5997bda3",
5
5
  "$schema_version": 1,
6
- "$published_version": "0.1.41",
6
+ "$published_version": "0.1.42",
7
7
  "$registry": "ghcr.io/pleri"
8
8
  }
@@ -2155,7 +2155,37 @@ let _spaCacheMtime = 0;
2155
2155
  // would 404 through host-cp returning the SPA shell — observed during
2156
2156
  // M5 dogfood: clicking Dispatch on /world/<id> hit /dispatch directly,
2157
2157
  // host-cp had no handler, and the SPA got HTML back instead of JSON.
2158
- const BOOTSTRAP_SCRIPT = `<script>(function(){try{var x=new XMLHttpRequest();x.open('GET','/api/bootstrap',false);x.send();if(x.status===200){var d=JSON.parse(x.responseText);document.cookie='olam_host_cp_token='+d.token+'; path=/; samesite=strict';}}catch(e){console.error('[host-cp bootstrap]',e);}var HN=['/api/bootstrap','/api/worlds','/api/projects','/api/workspaces','/api/workspaces/match','/api/auth','/health'];var WP=['/api/','/session/','/hooks/','/dispatch','/lanes','/codex/','/review/'];function sr(p){if(typeof p!=='string')return false;if(p.startsWith('/api/world/'))return false;for(var i=0;i<HN.length;i++){var n=HN[i];if(p===n||p.startsWith(n+'?')||p.startsWith(n+'/'))return false;}for(var j=0;j<WP.length;j++){var w=WP[j];if(p===w||p===w.replace(/\\/$/,'')||p.startsWith(w)||p.startsWith(w.replace(/\\/$/,'')+'?')||p.startsWith(w.replace(/\\/$/,'')+'/'))return true;}return false;}function wid(){var p=location.pathname;var m=p.match(/^\\/(world|inbox)\\/([^/?#]+)/);if(m)return m[2];if(/^\\/(?:worlds?|workspaces?|world|sandbox|inbox|plan|design|assets|api|health|favicon)($|\\/|\\?)/.test(p))return null;var r=p.match(/^\\/([a-z][a-z0-9-]+)(?:\\/|$|\\?)/);return r?r[1]:null;}function rw(p){var w=wid();return w?'/api/world/'+w+p:p;}var of=window.fetch.bind(window);window.fetch=function(input,init){if(typeof input==='string'&&sr(input))return of(rw(input),init);if(input&&typeof input.url==='string'&&sr(input.url))return of(new Request(rw(input.url),input),init);return of(input,init);};var OE=window.EventSource;if(OE){window.EventSource=function(u,i){var s=u;if(typeof s==='string'&&sr(s))s=rw(s);return new OE(s,i);};window.EventSource.prototype=OE.prototype;window.EventSource.CONNECTING=OE.CONNECTING;window.EventSource.OPEN=OE.OPEN;window.EventSource.CLOSED=OE.CLOSED;}})();</script>`;
2158
+ // SPA bootstrap script runs INLINE before any other script tag so it
2159
+ // can wrap window.fetch / window.EventSource before the SPA bundle loads.
2160
+ //
2161
+ // Three responsibilities:
2162
+ //
2163
+ // (1) Cookie sync: read /api/bootstrap synchronously to seed
2164
+ // `olam_host_cp_token`. The SPA's fetch calls then carry the
2165
+ // cookie automatically.
2166
+ //
2167
+ // (2) Path rewriting: `fetch('/session/<id>/state')` and similar
2168
+ // host-native short URLs get rewritten to the world-scoped form
2169
+ // `/api/world/<wid>/...` so host-cp's path-segment routing
2170
+ // dispatches them to the right per-world CP. EventSource gets
2171
+ // the same treatment for `/api/stream`, etc.
2172
+ //
2173
+ // (3) Auth-recovery: when a fetch returns 401 (the canonical signal
2174
+ // that the operator's cookie is stale — e.g. after an
2175
+ // `olam host-cp stop && start` rotates the token), re-read
2176
+ // /api/bootstrap. If the token changed, write the fresh cookie
2177
+ // and `location.reload()`. The SPA gets a clean restart with
2178
+ // the new auth context. This avoids the dogfood class where a
2179
+ // host-cp restart left the dashboard's readiness ladder stuck
2180
+ // at "Created" because the SPA's state poll silently 401'd and
2181
+ // no UI cue suggested a hard-reload.
2182
+ //
2183
+ // Guards against reload storms: a single `reloading` flag in the
2184
+ // closure prevents N concurrent 401s from triggering N reloads,
2185
+ // and the token-comparison check skips reload when the cookie
2186
+ // already matches (so non-rotation 401s — e.g. genuine auth
2187
+ // failures — don't cause a refresh loop).
2188
+ const BOOTSTRAP_SCRIPT = `<script>(function(){function ck(){var m=document.cookie.match(/olam_host_cp_token=([^;]+)/);return m?m[1]:'';}function sw(t){document.cookie='olam_host_cp_token='+t+'; path=/; samesite=strict';}try{var x=new XMLHttpRequest();x.open('GET','/api/bootstrap',false);x.send();if(x.status===200){var d=JSON.parse(x.responseText);sw(d.token);}}catch(e){console.error('[host-cp bootstrap]',e);}var reloading=false;function recover(){if(reloading)return;try{var x=new XMLHttpRequest();x.open('GET','/api/bootstrap',false);x.send();if(x.status===200){var d=JSON.parse(x.responseText);if(d.token&&ck()!==d.token){reloading=true;sw(d.token);console.warn('[host-cp auth recover] token rotated; reloading');location.reload();}}}catch(e){console.error('[host-cp auth recover]',e);}}var HN=['/api/bootstrap','/api/worlds','/api/projects','/api/workspaces','/api/workspaces/match','/api/auth','/health'];var WP=['/api/','/session/','/hooks/','/dispatch','/lanes','/codex/','/review/'];function sr(p){if(typeof p!=='string')return false;if(p.startsWith('/api/world/'))return false;for(var i=0;i<HN.length;i++){var n=HN[i];if(p===n||p.startsWith(n+'?')||p.startsWith(n+'/'))return false;}for(var j=0;j<WP.length;j++){var w=WP[j];if(p===w||p===w.replace(/\\/$/,'')||p.startsWith(w)||p.startsWith(w.replace(/\\/$/,'')+'?')||p.startsWith(w.replace(/\\/$/,'')+'/'))return true;}return false;}function wid(){var p=location.pathname;var m=p.match(/^\\/(world|inbox)\\/([^/?#]+)/);if(m)return m[2];if(/^\\/(?:worlds?|workspaces?|world|sandbox|inbox|plan|design|assets|api|health|favicon)($|\\/|\\?)/.test(p))return null;var r=p.match(/^\\/([a-z][a-z0-9-]+)(?:\\/|$|\\?)/);return r?r[1]:null;}function rw(p){var w=wid();return w?'/api/world/'+w+p:p;}var of=window.fetch.bind(window);window.fetch=function(input,init){var pr;if(typeof input==='string'&&sr(input))pr=of(rw(input),init);else if(input&&typeof input.url==='string'&&sr(input.url))pr=of(new Request(rw(input.url),input),init);else pr=of(input,init);return pr.then(function(res){if(res&&res.status===401)recover();return res;});};var OE=window.EventSource;if(OE){window.EventSource=function(u,i){var s=u;if(typeof s==='string'&&sr(s))s=rw(s);var es=new OE(s,i);es.addEventListener('error',function(){if(es.readyState===OE.CLOSED)recover();});return es;};window.EventSource.prototype=OE.prototype;window.EventSource.CONNECTING=OE.CONNECTING;window.EventSource.OPEN=OE.OPEN;window.EventSource.CLOSED=OE.CLOSED;}})();</script>`;
2159
2189
 
2160
2190
  async function renderSpaShell(filePath) {
2161
2191
  const stat = fs.statSync(filePath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pleri/olam-cli",
3
- "version": "0.1.41",
3
+ "version": "0.1.42",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "olam": "./dist/index.js"