@1agh/maude 1.3.0 → 1.3.1

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.
@@ -205,7 +205,7 @@
205
205
  // module, its tokens, its components CSS and its meta as separate
206
206
  // requests. Getting the document through and nothing else is what
207
207
  // "refused to connect" looks like from the outside.
208
- const cap = params.get('t') || '';
208
+ let cap = params.get('t') || '';
209
209
  // THE BASE THIS DOCUMENT WAS SERVED FROM, not the origin root.
210
210
  //
211
211
  // The fleet's canvas origin puts the project in the PATH
@@ -223,7 +223,7 @@
223
223
  return cap ? abs + (abs.includes('?') ? '&' : '?') + 't=' + encodeURIComponent(cap) : abs;
224
224
  };
225
225
  const canvasQuery = shaParam ? ('?sha=' + encodeURIComponent(shaParam)) : '';
226
- const canvasUrl = canvasRel ? withCap('/' + designRel + '/' + canvasRel + canvasQuery) : null;
226
+ let canvasUrl = canvasRel ? withCap('/' + designRel + '/' + canvasRel + canvasQuery) : null;
227
227
  const myFileKey = canvasRel ? (designRel + '/' + canvasRel) : null;
228
228
  // True while an `ai-activity` entry is live for THIS canvas (an agent is
229
229
  // running /design:edit|new on it). Mirrors ai-banner's gate: parent relays
@@ -250,6 +250,19 @@
250
250
  // The panel just optimistically applied an edit → skip the redundant
251
251
  // follow-up module reload (set here, parent-verified).
252
252
  lastCssOptimisticAt = Date.now();
253
+ } else if (m.dgn === 'canvas-cap') {
254
+ // A re-minted capability (it expires; app.jsx refreshes it). Every
255
+ // URL built from here on carries it, and asking for this shell
256
+ // document with it re-plants the origin's cookie — the one module
257
+ // imports, assets and the live sockets fall back to. Without this an
258
+ // open canvas stopped loading and updating once its first capability
259
+ // expired. Only a well-formed token, and only in the cloud (a
260
+ // desktop canvas never had one).
261
+ const t = m.t;
262
+ if (!cap || typeof t !== 'string' || t.length > 4096 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(t)) return;
263
+ cap = t;
264
+ if (canvasRel) canvasUrl = withCap('/' + designRel + '/' + canvasRel + canvasQuery);
265
+ fetch(withCap('/_canvas-shell.html'), { cache: 'no-store', credentials: 'same-origin' }).catch(() => {});
253
266
  }
254
267
  });
255
268
 
@@ -394,12 +407,22 @@
394
407
  if (msg.type !== 'canvas-hmr') return;
395
408
  if (msg.mode === 'css') {
396
409
  const v = msg.version || Date.now();
397
- // Match by exact filename when we have one; otherwise refresh all.
398
- const targetFile = (msg.file || '').split('/').pop();
410
+ // Match by PATH when we have one; otherwise refresh all. By path,
411
+ // not by file name: every design system has a `tokens.css`, and
412
+ // a change to one canvas's imported `system/<a>/tokens.css`
413
+ // "matched" the shell's link to `system/<b>/tokens.css` — which
414
+ // swapped the wrong sheet and skipped the reload below that the
415
+ // changed one needed (plan T31/L16).
416
+ const changed = msg.file ? '/' + msg.file : '';
399
417
  let matched = false;
400
418
  for (const link of document.querySelectorAll('link[rel="stylesheet"]')) {
401
419
  const href = link.getAttribute('href') || '';
402
- if (!targetFile || href.includes(targetFile)) {
420
+ if (!href) continue;
421
+ let linkPath = '';
422
+ try {
423
+ linkPath = decodeURIComponent(new URL(href, location.href).pathname);
424
+ } catch {}
425
+ if (!changed || linkPath.endsWith(changed)) {
403
426
  const base = href.split('?')[0];
404
427
  link.setAttribute('href', base + '?v=' + v);
405
428
  matched = true;
@@ -416,7 +439,21 @@
416
439
  if (!matched && msg.file && canvasRel) {
417
440
  const cssDir = msg.file.replace(/[^/]+$/, '');
418
441
  const canvasDir = canvasRel.replace(/[^/]+$/, '');
419
- if (cssDir === canvasDir) location.reload();
442
+ if (cssDir === canvasDir) {
443
+ location.reload();
444
+ } else {
445
+ // …and a stylesheet imported from ANYWHERE else (a design
446
+ // system's tokens.css) is inlined the same way. The module's
447
+ // style tag names what it inlined; re-import so it re-injects.
448
+ // (Canvas script could add names here, but that can only
449
+ // FORCE a reload — the safe direction.)
450
+ var bundled = document.querySelector('style[data-canvas-css="bundled"]');
451
+ var names = bundled && bundled.dataset.canvasCssSources ? bundled.dataset.canvasCssSources.split('|') : [];
452
+ if (names.indexOf(msg.file) !== -1) {
453
+ if (window.__maudeCanvasRuntime && window.__maudeCanvasRuntime.remount) softReload(v);
454
+ else location.reload();
455
+ }
456
+ }
420
457
  }
421
458
  } else if (msg.mode === 'module' || msg.mode === 'hard') {
422
459
  // Only reload when the change touches *this* canvas (or `_lib`).
@@ -443,7 +480,11 @@
443
480
  // direction; it can never suppress one.)
444
481
  var hasComps = false;
445
482
  try { hasComps = !!(window.__maude_comps__ && window.__maude_comps__().length); } catch (err) { hasComps = false; }
446
- if (!hasComps && Date.now() - lastCssOptimisticAt < 1500) return;
483
+ // …but NEVER a sync write (`remote`): it can carry a
484
+ // teammate's change merged under this person's own edit (a
485
+ // lost race re-applied onto theirs), and skipping it left
486
+ // their change off this canvas until a manual reload.
487
+ if (!hasComps && !msg.remote && Date.now() - lastCssOptimisticAt < 1500) return;
447
488
  }
448
489
  // Phase 30 (F4) — prefer an in-place hot-swap for ANY canvas-body
449
490
  // (`module`) change whenever the canvas runtime is mounted: the