@malloydata/malloyyo 0.2.9 → 0.2.10

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.
Files changed (2) hide show
  1. package/dist/index.js +52 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2262,7 +2262,8 @@ function makeBundler() {
2262
2262
  };
2263
2263
  }
2264
2264
  var html = (body, title) => `<!doctype html><html><head><meta charset="utf-8"><title>${title}</title><meta name="viewport" content="width=device-width,initial-scale=1"></head><body style="margin:0">${body}</body></html>`;
2265
- function parentShell(dash, frameBase, all) {
2265
+ function parentShell(dash, frameBase, all, initialGivens) {
2266
+ const givensQs = Object.entries(initialGivens).map(([k, v]) => `&${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("");
2266
2267
  const d = JSON.stringify(dash.name);
2267
2268
  const fb = JSON.stringify(frameBase);
2268
2269
  const nav = all.length > 1 ? `<nav style="display:flex;gap:4px;align-items:center;padding:8px 12px;background:#f6f7f9;border-bottom:1px solid #e2e4e8;font:13px system-ui,sans-serif"><span style="color:#888;margin-right:8px">Dashboards</span>` + all.map((x) => {
@@ -2270,11 +2271,20 @@ function parentShell(dash, frameBase, all) {
2270
2271
  return `<a href="/?d=${encodeURIComponent(x.name)}" style="padding:4px 10px;border-radius:6px;text-decoration:none;${on ? "background:#1a1a1a;color:#fff" : "color:#333"}">${esc(x.manifest.title || x.name)}</a>`;
2271
2272
  }).join("") + `</nav>` : "";
2272
2273
  return html(
2273
- `<div style="display:flex;flex-direction:column;height:100vh">` + nav + `<iframe id="f" sandbox="allow-scripts allow-same-origin" src="${frameBase}/frame?d=${encodeURIComponent(dash.name)}" style="border:0;flex:1;width:100%"></iframe></div><script>
2274
+ `<div style="display:flex;flex-direction:column;height:100vh">` + nav + `<iframe id="f" sandbox="allow-scripts allow-same-origin" src="${frameBase}/frame?d=${encodeURIComponent(dash.name)}${givensQs}" style="border:0;flex:1;width:100%"></iframe></div><script>
2274
2275
  const f=document.getElementById('f');
2276
+ try{new EventSource('/events').onmessage=()=>location.reload();}catch(e){}
2275
2277
  window.addEventListener('message',async(e)=>{
2276
2278
  if(e.source!==f.contentWindow||e.origin!==${fb})return;
2277
- const m=e.data; if(!m||m.type!=='run')return;
2279
+ const m=e.data;
2280
+ if(m&&m.type==='givens'){
2281
+ const u=new URL(location.href); u.search='';
2282
+ u.searchParams.set('d',${d});
2283
+ for(const [k,v] of Object.entries(m.givens)) u.searchParams.set(k,String(v));
2284
+ history.replaceState(null,'',u.pathname+u.search);
2285
+ return;
2286
+ }
2287
+ if(!m||m.type!=='run')return;
2278
2288
  let out;
2279
2289
  try{
2280
2290
  const res=await fetch('/api/run',{method:'POST',headers:{'content-type':'application/json'},
@@ -2287,9 +2297,14 @@ window.addEventListener('message',async(e)=>{
2287
2297
  dash.manifest.title
2288
2298
  );
2289
2299
  }
2290
- function frameDoc(dash) {
2300
+ function givensFromUrl(url4) {
2301
+ const g = {};
2302
+ for (const [k, v] of url4.searchParams) if (k !== "d") g[k] = v;
2303
+ return g;
2304
+ }
2305
+ function frameDoc(dash, initialGivens) {
2291
2306
  return html(
2292
- `<div id="root"></div><script>window.__MANIFEST__=${JSON.stringify(dash.manifest)}</script><script src="/bundle.js?d=${encodeURIComponent(dash.name)}"></script>`,
2307
+ `<div id="root"></div><script>window.__MANIFEST__=${JSON.stringify(dash.manifest)};window.__INITIAL_GIVENS__=${JSON.stringify(initialGivens)}</script><script src="/bundle.js?d=${encodeURIComponent(dash.name)}"></script>`,
2293
2308
  dash.manifest.title
2294
2309
  );
2295
2310
  }
@@ -2304,17 +2319,37 @@ async function serveDashboard(opts) {
2304
2319
  const port = opts.port ?? 4173;
2305
2320
  const framePort = port + 1;
2306
2321
  const frameBase = `http://localhost:${framePort}`;
2307
- const dashboards = discoverDashboards(root);
2322
+ let dashboards = discoverDashboards(root);
2308
2323
  if (dashboards.length === 0) {
2309
2324
  throw new Error(`No dashboards found under ${path4.join(root, "dashboards")}/`);
2310
2325
  }
2311
- const byName = new Map(dashboards.map((d) => [d.name, d]));
2326
+ let byName = new Map(dashboards.map((d) => [d.name, d]));
2312
2327
  const runner = await makeRunner(root);
2313
2328
  if (!runner.entryExists()) {
2314
2329
  throw new Error(`No index.malloy at ${root} \u2014 run this from a Malloy model repo.`);
2315
2330
  }
2316
2331
  const bundle = makeBundler();
2317
2332
  const pick = (url4) => byName.get(url4.searchParams.get("d") ?? dashboards[0].name) ?? dashboards[0];
2333
+ const sseClients = /* @__PURE__ */ new Set();
2334
+ const notifyReload = () => {
2335
+ for (const c of sseClients) c.write("data: reload\n\n");
2336
+ };
2337
+ let debounce;
2338
+ try {
2339
+ fs3.watch(root, { recursive: true }, (_evt, filename) => {
2340
+ const f = filename?.toString() ?? "";
2341
+ if (!f.endsWith(".malloy") && !f.includes("dashboards")) return;
2342
+ clearTimeout(debounce);
2343
+ debounce = setTimeout(() => {
2344
+ dashboards = discoverDashboards(root);
2345
+ byName = new Map(dashboards.map((d) => [d.name, d]));
2346
+ console.error(` \u21BB ${f} changed \u2014 reloading`);
2347
+ notifyReload();
2348
+ }, 150);
2349
+ });
2350
+ } catch (e) {
2351
+ console.error(` (file watch unavailable: ${e.message} \u2014 edits won't auto-reload)`);
2352
+ }
2318
2353
  const handler = async (req, res) => {
2319
2354
  const onFramePort = (req.socket.localPort ?? port) === framePort;
2320
2355
  const url4 = new URL(req.url ?? "/", `http://localhost:${onFramePort ? framePort : port}`);
@@ -2325,15 +2360,22 @@ async function serveDashboard(opts) {
2325
2360
  try {
2326
2361
  if (onFramePort) {
2327
2362
  if (url4.pathname === "/frame") {
2328
- return send(200, "text/html; charset=utf-8", frameDoc(pick(url4)));
2363
+ return send(200, "text/html; charset=utf-8", frameDoc(pick(url4), givensFromUrl(url4)));
2329
2364
  }
2330
2365
  if (url4.pathname === "/bundle.js") {
2331
2366
  return send(200, "application/javascript; charset=utf-8", await bundle(pick(url4)));
2332
2367
  }
2333
2368
  return send(404, "text/plain", "not found");
2334
2369
  }
2370
+ if (url4.pathname === "/events") {
2371
+ res.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache", connection: "keep-alive" });
2372
+ res.write("retry: 1000\n\n");
2373
+ sseClients.add(res);
2374
+ req.on("close", () => sseClients.delete(res));
2375
+ return;
2376
+ }
2335
2377
  if (url4.pathname === "/") {
2336
- return send(200, "text/html; charset=utf-8", parentShell(pick(url4), frameBase, dashboards));
2378
+ return send(200, "text/html; charset=utf-8", parentShell(pick(url4), frameBase, dashboards, givensFromUrl(url4)));
2337
2379
  }
2338
2380
  if (url4.pathname === "/api/run" && req.method === "POST") {
2339
2381
  const { d, query, givens } = JSON.parse(await readBody(req));
@@ -2367,7 +2409,7 @@ async function serveDashboard(opts) {
2367
2409
  }
2368
2410
 
2369
2411
  // package.json
2370
- var version = "0.2.9";
2412
+ var version = "0.2.10";
2371
2413
 
2372
2414
  // src/index.ts
2373
2415
  function shortSha(sha) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloyyo",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Publish Malloy models to a Malloyyo instance",
5
5
  "license": "MIT",
6
6
  "repository": {