@malloy-publisher/server 0.0.197-dev → 0.0.197

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 (60) hide show
  1. package/README.docker.md +88 -20
  2. package/README.md +15 -0
  3. package/build.ts +16 -0
  4. package/dist/app/api-doc.yaml +20 -3
  5. package/dist/app/assets/EnvironmentPage-BVkQH_xQ.js +1 -0
  6. package/dist/app/assets/HomePage-BgH9UkjK.js +1 -0
  7. package/dist/app/assets/MainPage-DiBxABem.js +2 -0
  8. package/dist/app/assets/ModelPage-oS70fj83.js +1 -0
  9. package/dist/app/assets/PackagePage-F_qLDAdv.js +1 -0
  10. package/dist/app/assets/RouteError-WqpffppN.js +1 -0
  11. package/dist/app/assets/WorkbookPage-_YmC-ebR.js +1 -0
  12. package/dist/app/assets/{core-w79IMXAG.es-Bd0UlzOL.js → core-B8L9xCYT.es-BcRLJTnC.js} +14 -14
  13. package/dist/app/assets/index-BMViiwtJ.js +451 -0
  14. package/dist/app/assets/{index-C513UodQ.js → index-C3XPaTaS.js} +15 -15
  15. package/dist/app/assets/index-rg8Ok8nl.js +1803 -0
  16. package/dist/app/assets/{index.umd-BMeMPq_9.js → index.umd-CCAfKkxY.js} +1 -1
  17. package/dist/app/index.html +2 -3
  18. package/dist/default-publisher.config.json +23 -0
  19. package/dist/instrumentation.mjs +1 -3
  20. package/dist/server.mjs +958 -177
  21. package/package.json +11 -12
  22. package/publisher.config.example.bigquery.json +33 -0
  23. package/publisher.config.example.duckdb.json +23 -0
  24. package/publisher.config.json +1 -11
  25. package/src/config.spec.ts +225 -0
  26. package/src/config.ts +96 -2
  27. package/src/controller/connection.controller.ts +1 -1
  28. package/src/default-publisher.config.json +23 -0
  29. package/src/errors.spec.ts +42 -0
  30. package/src/errors.ts +8 -0
  31. package/src/health.ts +26 -0
  32. package/src/logger.ts +1 -3
  33. package/src/pg_helpers.spec.ts +226 -0
  34. package/src/pg_helpers.ts +129 -0
  35. package/src/server-old.ts +1119 -0
  36. package/src/server.ts +36 -0
  37. package/src/service/connection.spec.ts +6 -4
  38. package/src/service/connection.ts +8 -3
  39. package/src/service/connection_config.ts +2 -2
  40. package/src/service/environment.ts +53 -25
  41. package/src/service/environment_store.spec.ts +19 -0
  42. package/src/service/environment_store.ts +21 -2
  43. package/src/service/package.ts +4 -3
  44. package/src/storage/StorageManager.ts +71 -11
  45. package/src/storage/duckdb/schema.ts +41 -0
  46. package/src/utils.ts +11 -0
  47. package/tests/harness/rest_e2e.ts +2 -2
  48. package/tests/integration/legacy_routes/legacy_routes.integration.spec.ts +259 -0
  49. package/tests/unit/duckdb/attached_databases.test.ts +5 -5
  50. package/tests/unit/duckdb/legacy_schema_migration.test.ts +194 -0
  51. package/tests/unit/storage/StorageManager.test.ts +166 -0
  52. package/dist/app/assets/EnvironmentPage-1j6QDWAy.js +0 -1
  53. package/dist/app/assets/HomePage-DMop21VG.js +0 -1
  54. package/dist/app/assets/MainPage-BbE8ETz1.js +0 -2
  55. package/dist/app/assets/ModelPage-D2jvfe3t.js +0 -1
  56. package/dist/app/assets/PackagePage-BbnhGoD3.js +0 -1
  57. package/dist/app/assets/RouteError-D3LGEZ3i.js +0 -1
  58. package/dist/app/assets/WorkbookPage-DttVIj4u.js +0 -1
  59. package/dist/app/assets/index-5K9YjIxF.js +0 -456
  60. package/dist/app/assets/index-DIgzgp69.js +0 -1742
package/README.docker.md CHANGED
@@ -1,32 +1,100 @@
1
- # Creating a Publisher Docker Image
1
+ # Publisher in Docker
2
2
 
3
- There are 2 docker files in the repo. A base `production.docker` which creates the base image and `malloy-samples.docker` which is layered on top and copies the malloy samples into the Docker image so they can be served by the publisher.
3
+ The canonical build is the root [`Dockerfile`](../../Dockerfile) and the CI smoke test (`docker_smoke_test` in `.github/workflows/build.yml`) builds and runs that exact image. The two-port REST + MCP server, the Snowflake ADBC driver, the DuckDB CLI, and the production app bundle all ship in it.
4
4
 
5
- To create a Docker image for your own packages, follow the example of `docker/malloy-samples.docker` which copies in the publisher config and malloy files.
5
+ A short Docker section in the [repo root README](../../README.md#docker) covers the canonical build + run; this doc goes deeper on runtime layout, environment variables, persistent storage, and credentials.
6
6
 
7
- ## To create & run the malloy-samples Docker image:
7
+ ## Build and run
8
8
 
9
- 1. Clone the Publisher repository + malloy-sample submodule as outline in the README.
9
+ ```bash
10
+ docker build -t malloy-publisher .
11
+ docker run -d \
12
+ --name malloy-publisher \
13
+ -p 4000:4000 -p 4040:4040 \
14
+ -v $(pwd)/publisher.config.json:/publisher/publisher.config.json:ro \
15
+ malloy-publisher
16
+ ```
17
+
18
+ Once `/api/v0/status` reports `operationalState: "serving"`, the REST API is at `http://localhost:4000` and MCP at `http://localhost:4040/mcp`.
19
+
20
+ If you don't have a config of your own yet, copy [`packages/server/publisher.config.example.duckdb.json`](./publisher.config.example.duckdb.json) (DuckDB-only samples, no credentials required) and mount that. There's also a [`publisher.config.example.bigquery.json`](./publisher.config.example.bigquery.json) sibling for the BigQuery samples.
21
+
22
+ ## Pre-built image
23
+
24
+ If you don't want to build the image yourself, the official pre-built image is published to Docker Hub under the **`ms2data/`** namespace (not `malloydata/`):
10
25
 
11
- 2. Build the Docker imagee using the provided Dockerfiles:
26
+ ```bash
27
+ docker pull ms2data/malloy-publisher
28
+ docker run -d \
29
+ --name malloy-publisher \
30
+ -p 4000:4000 -p 4040:4040 \
31
+ -v $(pwd)/publisher.config.json:/publisher/publisher.config.json:ro \
32
+ ms2data/malloy-publisher
33
+ ```
12
34
 
13
- ```bash
14
- docker build -t malloy-publisher:latest -f docker/production.docker .
15
- docker build -t malloy-samples:latest -f docker/malloy-samples.docker .
16
- ```
35
+ See the [Docker Hub tags page](https://hub.docker.com/r/ms2data/malloy-publisher/tags) for available versions. Tag-scheme guidance (`:latest`, `:X.Y.Z`, `:next`) lives in the root README's [Docker section](../../README.md#docker).
17
36
 
18
- 3. Run the Docker container.
19
- The Publisher server runs at port 4000, the MCP server at port 4040.
37
+ ## Runtime layout
20
38
 
21
- ```bash
22
- docker run -p 4000:4000 -p 4040:4040 malloy-samples:latest
23
- ```
39
+ | Path inside container | What's there |
40
+ |---|---|
41
+ | `/publisher/` | `WORKDIR`. The server reads `<WORKDIR>/publisher.config.json` by default — that's the file you mount. |
42
+ | `/publisher/packages/server/dist/` | The bundled server (built by `bun run build` in CI). |
43
+ | `/publisher/packages/app/dist/` | The static SPA the server serves. |
44
+ | `/publisher/publisher_data/` | Per-environment package clones, DuckDB extension cache, and per-package sandbox DBs. Created at runtime; **persist this as a named volume if you want first-run sample clones to survive a container restart.** |
45
+ | `/root/.duckdb/` | DuckDB CLI + extension install dir. Bundled into the image. |
24
46
 
25
- 4. (Optional) For BigQuery access, mount your GCP credentials.
26
- Note that you cannot use personal credentials- only service account credentials can be used in the docker image.
47
+ To keep `publisher_data/` across restarts:
27
48
 
28
49
  ```bash
29
- docker run -p 4000:4000 -p 4040:4040 \
30
- -v /path/to/your/service_credentials.json:/app/gcp-credentials/key.json \
31
- malloy-samples:latest
50
+ docker run -d \
51
+ --name malloy-publisher \
52
+ -p 4000:4000 -p 4040:4040 \
53
+ -v $(pwd)/publisher.config.json:/publisher/publisher.config.json:ro \
54
+ -v publisher_data:/publisher/publisher_data \
55
+ malloy-publisher
32
56
  ```
57
+
58
+ The first request after a fresh start clones sample packages from GitHub — a named volume turns that one-time cost into a one-time cost across all container lifecycles.
59
+
60
+ For the same pattern as a complete Compose file (with a healthcheck against `/api/v0/status` and both ports mapped), see [`docker-compose.example.yml`](../../docker-compose.example.yml) at the repo root.
61
+
62
+ ## Configuration via environment variables
63
+
64
+ All flags exposed by `bin/malloy-publisher --help` have an equivalent env var, so they're easy to set from `docker run -e` or compose:
65
+
66
+ | Env var | Equivalent flag | Default | Purpose |
67
+ |---|---|---|---|
68
+ | `PUBLISHER_PORT` | `--port <n>` | `4000` | REST API port. |
69
+ | `PUBLISHER_HOST` | `--host <h>` | `0.0.0.0` | Bind address. |
70
+ | `MCP_PORT` | `--mcp_port <n>` | `4040` | MCP API port. |
71
+ | `SERVER_ROOT` | `--server_root <path>` | `.` (cwd) at the server level; overridden to `/publisher` by the bundled CMD | Directory the server treats as its working dir. The image's CMD passes `--server_root /publisher` explicitly so the zero-arg `npx` bundled-default trigger doesn't fire inside the container. If you override CMD with your own entrypoint, set `SERVER_ROOT` yourself to keep this behaviour. |
72
+ | `PUBLISHER_CONFIG_PATH` | `--config <path>` | unset | Absolute path to a `publisher.config.json`. Wins over `<SERVER_ROOT>/publisher.config.json`. Use this if you want to mount your config somewhere other than `/publisher/`. |
73
+ | `INITIALIZE_STORAGE` | `--init` | `false` | Wipes persisted storage state on startup. Useful when `frozenConfig: false` has let `publisher_data/` drift from the on-disk config; destructive otherwise. |
74
+ | `SHUTDOWN_DRAIN_DURATION_SECONDS` | — | `0` | On SIGTERM, how long to keep accepting requests while draining before closing server sockets. Set this to your typical request duration to avoid 502s from K8s rolling deploys. |
75
+ | `SHUTDOWN_GRACEFUL_CLOSE_TIMEOUT_SECONDS` | — | `0` | Additional grace period after server close before `process.exit`. |
76
+ | `GOOGLE_APPLICATION_CREDENTIALS` | — | unset | Path inside the container to a GCP service-account JSON. Required for BigQuery-backed environments. Personal user credentials don't work inside the container — use a service account. |
77
+
78
+ ## BigQuery credentials
79
+
80
+ To enable BigQuery samples or your own BigQuery connections, mount a service-account key and point `GOOGLE_APPLICATION_CREDENTIALS` at it:
81
+
82
+ ```bash
83
+ docker run -d \
84
+ --name malloy-publisher \
85
+ -p 4000:4000 -p 4040:4040 \
86
+ -v $(pwd)/publisher.config.json:/publisher/publisher.config.json:ro \
87
+ -v $(pwd)/gcp-sa.json:/etc/publisher/gcp-sa.json:ro \
88
+ -e GOOGLE_APPLICATION_CREDENTIALS=/etc/publisher/gcp-sa.json \
89
+ malloy-publisher
90
+ ```
91
+
92
+ The Dockerfile creates `/etc/publisher/` as an empty directory outside the application tree at `/publisher/`. By the convention this doc establishes, mount credential material there to keep it separated from the app — but any writable path inside the container works.
93
+
94
+ ## The CI Dockerfile (`docker/Dockerfile.ci`)
95
+
96
+ `docker/Dockerfile.ci` exists for the CI integration-test path (referenced from the repo's `docker-compose.yml`). It is **not** the production image and should not be used for deployment. Production users build the root [`Dockerfile`](../../Dockerfile).
97
+
98
+ ## Deprecated build paths
99
+
100
+ `docker/production.docker` and `docker/malloy-samples.docker` are leftover from a previous Docker layout. They are not built by CI, are not referenced by any current workflow, and produce a different image than what is deployed. Don't use them. They will be removed in a follow-up cleanup PR; the audit and tracking is in `publisher-audit-docker.md` (finding #1).
package/README.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  The Malloy Publisher Server is an Express.js server that provides an API for managing and accessing Malloy data models, packages, and queries
4
4
 
5
+ ## Configuration
6
+
7
+ `publisher.config.json` lives in this directory. The repository root also contains a symlink (`/publisher.config.json` → `./packages/server/publisher.config.json`) so that running the server from either location picks up the same config. Edit one and you've edited both.
8
+
9
+ For the BigQuery-enabled variant, see [`publisher.config.example.bigquery.json`](./publisher.config.example.bigquery.json) and the [Quick Start in the repo root README](../../README.md#quick-start).
10
+
11
+ ### Remaining deprecation warnings
12
+
13
+ Removing the unused `trino` CLI direct dep (it pulled in `@google-cloud/translate@0.7.x` → `request@2.x` → `har-validator` → `hawk` → `cryptiles`) cleaned the worst chain. About 25 `npm warn deprecated` lines remain on `npx @malloy-publisher/server` install, all upstream-owned:
14
+
15
+ - **npm CLI tooling**: `npmlog`, `gauge`, `are-we-there-yet`, `glob@7/8/10`, `rimraf@3`, `tar@6.2.1`, `inflight`, `@npmcli/move-file`, `node-domexception`, `querystring` — pulled in by npm itself and by `node-pre-gyp`/`node-gyp`. Not actionable from this repo.
16
+ - **`uuid@8.x` / `uuid@9.x`**: surfaced across multiple transitives (Malloy, AWS SDKs, others). Resolves when each upstream bumps to `uuid@11`.
17
+ - **`q@1.5.1`**: pulled in via `thrift` → `@databricks/sql` → `@malloydata/db-databricks`. Resolves when Databricks upgrades `@databricks/sql` past the thrift dep, or when we replace the Databricks driver.
18
+ - **`aws-sdk@2.1693.0`**: listed as a direct dep in `packages/server/package.json` but not imported anywhere in source — leftover, candidate for removal in a follow-up PR. The actual consumer is `@aws-sdk/client-s3` v3.
19
+
5
20
  ## K6 Test Presets
6
21
 
7
22
  The Malloy Publisher Server includes several K6 test presets to help you test its performance and stability.
package/build.ts CHANGED
@@ -29,6 +29,22 @@ await build({
29
29
 
30
30
  fs.cpSync("../app/dist", "./dist/app", { recursive: true });
31
31
 
32
+ // Ship a default publisher.config.json inside the bundle so that
33
+ // `npx @malloy-publisher/server` works with zero args (uses
34
+ // DuckDB-only samples). config.ts looks for this file next to
35
+ // server.mjs.
36
+ //
37
+ // IMPORTANT: keep `packages/server/src/default-publisher.config.json`
38
+ // in sync with `packages/server/publisher.config.json`. The two files
39
+ // have intentionally identical content — the committed one drives the
40
+ // dev workflow (`bun run start`, integration tests), the bundled one
41
+ // is the fallback for npx users with no config of their own. A drift
42
+ // here surfaces as "npx users see different samples than dev users."
43
+ fs.copyFileSync(
44
+ "./src/default-publisher.config.json",
45
+ "./dist/default-publisher.config.json",
46
+ );
47
+
32
48
  // Rename ESM outputs to .mjs so both Node and Bun can execute them
33
49
  fs.renameSync("./dist/server.js", "./dist/server.mjs");
34
50
  fs.renameSync("./dist/instrumentation.js", "./dist/instrumentation.mjs");
@@ -2498,11 +2498,28 @@ components:
2498
2498
  description: Whether the server is fully initialized and ready to serve requests
2499
2499
  operationalState:
2500
2500
  type: string
2501
- enum: [ "initializing", "serving", "draining" ]
2501
+ enum: [ "initializing", "serving", "degraded", "draining" ]
2502
2502
  description: Status of the server; initializing when the server is loading
2503
2503
  environments, packages and connections, serving when the server is
2504
- initialized and ready to serve requests, and draining when the
2505
- server is going to shut down
2504
+ initialized and ready to serve requests, degraded when initialization
2505
+ completed but one or more environments failed to load (the surviving
2506
+ environments are served; see failedEnvironments), and draining when
2507
+ the server is going to shut down
2508
+ failedEnvironments:
2509
+ type: array
2510
+ description: Environments that failed to initialize. Present only when
2511
+ operationalState is "degraded". Healthy environments are listed under
2512
+ "environments".
2513
+ items:
2514
+ type: object
2515
+ required: [name, error]
2516
+ properties:
2517
+ name:
2518
+ type: string
2519
+ description: Environment name as declared in publisher.config.json
2520
+ error:
2521
+ type: string
2522
+ description: Error message from the initialization failure
2506
2523
  frozenConfig:
2507
2524
  type: boolean
2508
2525
  description: Whether the server configuration is frozen (read-only mode). When
@@ -0,0 +1 @@
1
+ import{S as r,F as t,j as e,_ as i,a2 as o}from"./index-BMViiwtJ.js";function m(){const s=r(),{environmentName:n}=t();if(n){const a=i({environmentName:n});return e.jsx(o,{onSelectPackage:s,resourceUri:a})}else return e.jsx("div",{children:e.jsx("h2",{children:"Missing environment name"})})}export{m as default};
@@ -0,0 +1 @@
1
+ import{S as t,j as o,L as a}from"./index-BMViiwtJ.js";function s(){const n=t();return o.jsx(a,{onClickEnvironment:n})}export{s as default};
@@ -0,0 +1,2 @@
1
+ import{u as we,g as ke,r as u,R as Se,a as Pe,c as $,j as t,s as I,B as Ce,m as _,e as re,b as oe,d as se,f as ae,h as Ee,i as O,k as ie,T as K,l as G,n as Ie,o as Me,p as Re,q as le,t as ze,v as ne,w as De,x as Te,y as Be,z as A,A as L,M as $e,P as He,C as Le,D as Ne,E as Ae,F as ce,S as J,G as x,H as We,I as X,J as Oe,K as Z,X as Ve,N as Ue,O as de,Q as pe,U as ue,V as he,W as Qe,Y as Fe,Z as Xe}from"./index-BMViiwtJ.js";function Ye(e,r,n,o,s){const[a,i]=u.useState(()=>s&&n?n(e).matches:o?o(e).matches:r);return Pe(()=>{if(!n)return;const c=n(e),h=()=>{i(c.matches)};return h(),c.addEventListener("change",h),()=>{c.removeEventListener("change",h)}},[e,n]),a}const _e={...Se},fe=_e.useSyncExternalStore;function Ke(e,r,n,o,s){const a=u.useCallback(()=>r,[r]),i=u.useMemo(()=>{if(s&&n)return()=>n(e).matches;if(o!==null){const{matches:p}=o(e);return()=>p}return a},[a,e,o,s,n]),[c,h]=u.useMemo(()=>{if(n===null)return[a,()=>()=>{}];const p=n(e);return[()=>p.matches,m=>(p.addEventListener("change",m),()=>{p.removeEventListener("change",m)})]},[a,n,e]);return fe(h,c,i)}function me(e={}){const{themeId:r}=e;return function(o,s={}){let a=we();a&&r&&(a=a[r]||a);const i=typeof window<"u"&&typeof window.matchMedia<"u",{defaultMatches:c=!1,matchMedia:h=i?window.matchMedia:null,ssrMatchMedia:f=null,noSsr:p=!1}=ke({name:"MuiUseMediaQuery",props:s,theme:a});let m=typeof o=="function"?o(a):o;return m=m.replace(/^@media( ?)/m,""),m.includes("print")&&console.warn(["MUI: You have provided a `print` query to the `useMediaQuery` hook.","Using the print media query to modify print styles can lead to unexpected results.","Consider using the `displayPrint` field in the `sx` prop instead.","More information about `displayPrint` on our docs: https://mui.com/system/display/#display-in-print."].join(`
2
+ `)),(fe!==void 0?Ke:Ye)(m,c,h,f,p)}}me();const Ge=$(t.jsx("path",{d:"M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"})),Je=I(Ce,{name:"MuiBreadcrumbCollapsed"})(_(({theme:e})=>({display:"flex",marginLeft:`calc(${e.spacing(1)} * 0.5)`,marginRight:`calc(${e.spacing(1)} * 0.5)`,...e.palette.mode==="light"?{backgroundColor:e.palette.grey[100],color:e.palette.grey[700]}:{backgroundColor:e.palette.grey[700],color:e.palette.grey[100]},borderRadius:2,"&:hover, &:focus":{...e.palette.mode==="light"?{backgroundColor:e.palette.grey[200]}:{backgroundColor:e.palette.grey[600]}},"&:active":{boxShadow:e.shadows[0],...e.palette.mode==="light"?{backgroundColor:re(e.palette.grey[200],.12)}:{backgroundColor:re(e.palette.grey[600],.12)}}}))),Ze=I(Ge)({width:24,height:16});function qe(e){const{slots:r={},slotProps:n={},...o}=e,s=e;return t.jsx("li",{children:t.jsx(Je,{focusRipple:!0,...o,ownerState:s,children:t.jsx(Ze,{as:r.CollapsedIcon,ownerState:s,...n.collapsedIcon})})})}function et(e){return se("MuiBreadcrumbs",e)}const tt=oe("MuiBreadcrumbs",["root","ol","li","separator"]),rt=e=>{const{classes:r}=e;return ie({root:["root"],li:["li"],ol:["ol"],separator:["separator"]},et,r)},nt=I(K,{name:"MuiBreadcrumbs",slot:"Root",overridesResolver:(e,r)=>[{[`& .${tt.li}`]:r.li},r.root]})({}),ot=I("ol",{name:"MuiBreadcrumbs",slot:"Ol"})({display:"flex",flexWrap:"wrap",alignItems:"center",padding:0,margin:0,listStyle:"none"}),st=I("li",{name:"MuiBreadcrumbs",slot:"Separator"})({display:"flex",userSelect:"none",marginLeft:8,marginRight:8});function at(e,r,n,o){return e.reduce((s,a,i)=>(i<e.length-1?s=s.concat(a,t.jsx(st,{"aria-hidden":!0,className:r,ownerState:o,children:n},`separator-${i}`)):s.push(a),s),[])}const it=u.forwardRef(function(r,n){const o=ae({props:r,name:"MuiBreadcrumbs"}),{children:s,className:a,component:i="nav",slots:c={},slotProps:h={},expandText:f="Show path",itemsAfterCollapse:p=1,itemsBeforeCollapse:m=1,maxItems:y=8,separator:S="/",...H}=o,[M,P]=u.useState(!1),v={...o,component:i,expanded:M,expandText:f,itemsAfterCollapse:p,itemsBeforeCollapse:m,maxItems:y,separator:S},C=rt(v),R=Ee({elementType:c.CollapsedIcon,externalSlotProps:h.collapsedIcon,ownerState:v}),j=u.useRef(null),w=d=>{const k=()=>{P(!0);const b=j.current.querySelector("a[href],button,[tabindex]");b&&b.focus()};return m+p>=d.length?d:[...d.slice(0,m),t.jsx(qe,{"aria-label":f,slots:{CollapsedIcon:c.CollapsedIcon},slotProps:{collapsedIcon:R},onClick:k},"ellipsis"),...d.slice(d.length-p,d.length)]},z=u.Children.toArray(s).filter(d=>u.isValidElement(d)).map((d,k)=>t.jsx("li",{className:C.li,children:d},`child-${k}`));return t.jsx(nt,{ref:n,component:i,color:"textSecondary",className:O(C.root,a),ownerState:v,...H,children:t.jsx(ot,{className:C.ol,ref:j,ownerState:v,children:at(M||y&&z.length<=y?z:w(z),C.separator,S,v)})})});function lt(e,r,n){const o=r.getBoundingClientRect(),s=n&&n.getBoundingClientRect(),a=le(r);let i;if(r.fakeTransform)i=r.fakeTransform;else{const f=a.getComputedStyle(r);i=f.getPropertyValue("-webkit-transform")||f.getPropertyValue("transform")}let c=0,h=0;if(i&&i!=="none"&&typeof i=="string"){const f=i.split("(")[1].split(")")[0].split(",");c=parseInt(f[4],10),h=parseInt(f[5],10)}return e==="left"?s?`translateX(${s.right+c-o.left}px)`:`translateX(${a.innerWidth+c-o.left}px)`:e==="right"?s?`translateX(-${o.right-s.left-c}px)`:`translateX(-${o.left+o.width-c}px)`:e==="up"?s?`translateY(${s.bottom+h-o.top}px)`:`translateY(${a.innerHeight+h-o.top}px)`:s?`translateY(-${o.top-s.top+o.height-h}px)`:`translateY(-${o.top+o.height-h}px)`}function ct(e){return typeof e=="function"?e():e}function W(e,r,n){const o=ct(n),s=lt(e,r,o);s&&(r.style.webkitTransform=s,r.style.transform=s)}const dt=u.forwardRef(function(r,n){const o=G(),s={enter:o.transitions.easing.easeOut,exit:o.transitions.easing.sharp},a={enter:o.transitions.duration.enteringScreen,exit:o.transitions.duration.leavingScreen},{addEndListener:i,appear:c=!0,children:h,container:f,direction:p="down",easing:m=s,in:y,onEnter:S,onEntered:H,onEntering:M,onExit:P,onExited:v,onExiting:C,style:R,timeout:j=a,TransitionComponent:w=Ie,...z}=r,d=u.useRef(null),k=Me(Re(h),d,n),b=l=>g=>{l&&(g===void 0?l(d.current):l(d.current,g))},V=b((l,g)=>{W(p,l,f),De(l),S&&S(l,g)}),q=b((l,g)=>{const B=ne({timeout:j,style:R,easing:m},{mode:"enter"});l.style.webkitTransition=o.transitions.create("-webkit-transform",{...B}),l.style.transition=o.transitions.create("transform",{...B}),l.style.webkitTransform="none",l.style.transform="none",M&&M(l,g)}),D=b(H),T=b(C),E=b(l=>{const g=ne({timeout:j,style:R,easing:m},{mode:"exit"});l.style.webkitTransition=o.transitions.create("-webkit-transform",g),l.style.transition=o.transitions.create("transform",g),W(p,l,f),P&&P(l)}),U=b(l=>{l.style.webkitTransition="",l.style.transition="",v&&v(l)}),Q=l=>{i&&i(d.current,l)},N=u.useCallback(()=>{d.current&&W(p,d.current,f)},[p,f]);return u.useEffect(()=>{if(y||p==="down"||p==="right")return;const l=ze(()=>{d.current&&W(p,d.current,f)}),g=le(d.current);return g.addEventListener("resize",l),()=>{l.clear(),g.removeEventListener("resize",l)}},[p,y,f]),u.useEffect(()=>{y||N()},[y,N]),t.jsx(w,{nodeRef:d,onEnter:V,onEntered:D,onEntering:q,onExit:E,onExited:U,onExiting:T,addEndListener:Q,appear:c,in:y,timeout:j,...z,children:(l,{ownerState:g,...B})=>u.cloneElement(h,{ref:k,style:{visibility:l==="exited"&&!y?"hidden":void 0,...R,...h.props.style},...B})})});function pt(e){return se("MuiDrawer",e)}oe("MuiDrawer",["root","docked","paper","anchorLeft","anchorRight","anchorTop","anchorBottom","paperAnchorLeft","paperAnchorRight","paperAnchorTop","paperAnchorBottom","paperAnchorDockedLeft","paperAnchorDockedRight","paperAnchorDockedTop","paperAnchorDockedBottom","modal"]);const xe=(e,r)=>{const{ownerState:n}=e;return[r.root,(n.variant==="permanent"||n.variant==="persistent")&&r.docked,r.modal]},ut=e=>{const{classes:r,anchor:n,variant:o}=e,s={root:["root",`anchor${L(n)}`],docked:[(o==="permanent"||o==="persistent")&&"docked"],modal:["modal"],paper:["paper",`paperAnchor${L(n)}`,o!=="temporary"&&`paperAnchorDocked${L(n)}`]};return ie(s,pt,r)},ht=I($e,{name:"MuiDrawer",slot:"Root",overridesResolver:xe})(_(({theme:e})=>({zIndex:(e.vars||e).zIndex.drawer}))),ft=I("div",{shouldForwardProp:Le,name:"MuiDrawer",slot:"Docked",skipVariantsResolver:!1,overridesResolver:xe})({flex:"0 0 auto"}),mt=I(He,{name:"MuiDrawer",slot:"Paper",overridesResolver:(e,r)=>{const{ownerState:n}=e;return[r.paper,r[`paperAnchor${L(n.anchor)}`],n.variant!=="temporary"&&r[`paperAnchorDocked${L(n.anchor)}`]]}})(_(({theme:e})=>({overflowY:"auto",display:"flex",flexDirection:"column",height:"100%",flex:"1 0 auto",zIndex:(e.vars||e).zIndex.drawer,WebkitOverflowScrolling:"touch",position:"fixed",top:0,outline:0,variants:[{props:{anchor:"left"},style:{left:0}},{props:{anchor:"top"},style:{top:0,left:0,right:0,height:"auto",maxHeight:"100%"}},{props:{anchor:"right"},style:{right:0}},{props:{anchor:"bottom"},style:{top:"auto",left:0,bottom:0,right:0,height:"auto",maxHeight:"100%"}},{props:({ownerState:r})=>r.anchor==="left"&&r.variant!=="temporary",style:{borderRight:`1px solid ${(e.vars||e).palette.divider}`}},{props:({ownerState:r})=>r.anchor==="top"&&r.variant!=="temporary",style:{borderBottom:`1px solid ${(e.vars||e).palette.divider}`}},{props:({ownerState:r})=>r.anchor==="right"&&r.variant!=="temporary",style:{borderLeft:`1px solid ${(e.vars||e).palette.divider}`}},{props:({ownerState:r})=>r.anchor==="bottom"&&r.variant!=="temporary",style:{borderTop:`1px solid ${(e.vars||e).palette.divider}`}}]}))),ge={left:"right",right:"left",top:"down",bottom:"up"};function xt(e){return["left","right"].includes(e)}function gt({direction:e},r){return e==="rtl"&&xt(r)?ge[r]:r}const yt=u.forwardRef(function(r,n){const o=ae({props:r,name:"MuiDrawer"}),s=G(),a=Te(),i={enter:s.transitions.duration.enteringScreen,exit:s.transitions.duration.leavingScreen},{anchor:c="left",BackdropProps:h,children:f,className:p,elevation:m=16,hideBackdrop:y=!1,ModalProps:{BackdropProps:S,...H}={},onClose:M,open:P=!1,PaperProps:v={},SlideProps:C,TransitionComponent:R,transitionDuration:j=i,variant:w="temporary",slots:z={},slotProps:d={},...k}=o,b=u.useRef(!1);u.useEffect(()=>{b.current=!0},[]);const V=gt({direction:a?"rtl":"ltr"},c),D={...o,anchor:c,elevation:m,open:P,variant:w,...k},T=ut(D),E={slots:{transition:R,...z},slotProps:{paper:v,transition:C,...d,backdrop:Be(d.backdrop||{...h,...S},{transitionDuration:j})}},[U,Q]=A("root",{ref:n,elementType:ht,className:O(T.root,T.modal,p),shouldForwardComponentProp:!0,ownerState:D,externalForwardedProps:{...E,...k,...H},additionalProps:{open:P,onClose:M,hideBackdrop:y,slots:{backdrop:E.slots.backdrop},slotProps:{backdrop:E.slotProps.backdrop}}}),[N,l]=A("paper",{elementType:mt,shouldForwardComponentProp:!0,className:O(T.paper,v.className),ownerState:D,externalForwardedProps:E,additionalProps:{elevation:w==="temporary"?m:0,square:!0,...w==="temporary"&&{role:"dialog","aria-modal":"true"}}}),[g,B]=A("docked",{elementType:ft,ref:n,className:O(T.root,T.docked,p),ownerState:D,externalForwardedProps:E,additionalProps:k}),[ve,je]=A("transition",{elementType:dt,ownerState:D,externalForwardedProps:E,additionalProps:{in:P,direction:ge[V],timeout:j,appear:b.current}}),ee=t.jsx(N,{...l,children:f});if(w==="permanent")return t.jsx(g,{...B,children:ee});const te=t.jsx(ve,{...je,children:ee});return w==="persistent"?t.jsx(g,{...B,children:te}):t.jsx(U,{...Q,children:te})}),bt=me({themeId:Ne}),vt=$([t.jsx("path",{d:"M19 5v14H5V5zm0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2"},"0"),t.jsx("path",{d:"M14 17H7v-2h7zm3-4H7v-2h10zm0-4H7V7h10z"},"1")]),jt=$(t.jsx("path",{d:"M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"})),wt=$(t.jsx("path",{d:"M9.4 16.6 4.8 12l4.6-4.6L8 6l-6 6 6 6zm5.2 0 4.6-4.6-4.6-4.6L16 6l6 6-6 6z"})),kt=$(t.jsx("path",{d:"m9.17 6 2 2H20v10H4V6zM10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z"})),St=$(t.jsx("path",{d:"m12 5.69 5 4.5V18h-2v-6H9v6H7v-7.81zM12 3 2 12h3v8h6v-6h2v6h6v-8h3z"})),Pt=$(t.jsx("path",{d:"M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3z"}));function Y(e){return t.jsxs(Ae,{...e,viewBox:"0 0 24 24",sx:{fill:"none",...e.sx},children:[t.jsx("rect",{x:"3.25",y:"4.75",width:"17.5",height:"14.5",rx:"2.25",stroke:"currentColor",strokeWidth:"1.5"}),t.jsx("line",{x1:"8.5",y1:"5",x2:"8.5",y2:"19",stroke:"currentColor",strokeWidth:"1.5"})]})}function F({label:e,onClick:r}){return t.jsx(We,{clickable:!0,onClick:r,label:e,size:"small","aria-label":`Navigate to ${e}`,sx:{backgroundColor:"background.paper",color:"text.primary",fontWeight:500,fontSize:"0.875rem",height:32,cursor:"pointer",borderRadius:"4px",maxWidth:320,"& .MuiChip-label":{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},"&:hover":{backgroundColor:"grey.100"}}})}function Ct(){const e=ce(),r=e["*"],n=J();return!e.environmentName&&!e.packageName&&!r?null:t.jsx(x,{sx:{display:"flex",alignItems:"center",minWidth:0},children:t.jsxs(it,{"aria-label":"breadcrumb",separator:t.jsx(jt,{sx:{fontSize:14,color:"text.secondary"}}),children:[e.environmentName&&t.jsx(F,{label:e.environmentName,onClick:o=>n(`/${e.environmentName}/`,o)}),e.packageName&&t.jsx(F,{label:e.packageName,onClick:o=>n(`/${e.environmentName}/${e.packageName}/`,o)}),r&&t.jsx(F,{label:r,onClick:o=>n(`/${e.environmentName}/${e.packageName}/${r}`,o)})]})})}const Et=260,It=64;function ye({isCollapsed:e,onToggleCollapse:r,logoHeader:n}){return t.jsxs(x,{sx:{height:"100dvh",width:e?It:Et,flexShrink:0,display:"flex",flexDirection:"column",backgroundColor:"background.paper",transition:"width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",overflow:"hidden"},children:[t.jsx(Mt,{isCollapsed:e,onToggleCollapse:r,logoHeader:n}),t.jsxs(x,{sx:{flex:1,overflowY:"auto",overflowX:"hidden",py:1},children:[t.jsx(Rt,{isCollapsed:e}),t.jsx(zt,{isCollapsed:e})]}),t.jsx(Dt,{isCollapsed:e})]})}function Mt({isCollapsed:e,onToggleCollapse:r,logoHeader:n}){const o=J();return n?t.jsxs(x,{sx:{height:56,display:"flex",alignItems:"center",justifyContent:"space-between",px:e?0:2,flexShrink:0},children:[n,t.jsx(X,{size:"small",onClick:r,"aria-label":e?"Expand sidebar":"Collapse sidebar",children:t.jsx(Y,{fontSize:"small"})})]}):t.jsxs(x,{sx:{height:56,display:"flex",alignItems:"center",justifyContent:e?"center":"space-between",px:e?0:2,flexShrink:0},children:[t.jsxs(x,{onClick:s=>o("/",s),sx:{display:"flex",alignItems:"center",gap:1,cursor:"pointer",minWidth:0},children:[t.jsx(x,{component:"img",src:"/logo.svg",alt:"Malloy",sx:{width:24,height:24,flexShrink:0}}),!e&&t.jsx(K,{variant:"subtitle1",sx:{color:"text.primary",fontWeight:500,letterSpacing:"-0.025em",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},children:"Malloy Publisher"})]}),!e&&t.jsx(X,{size:"small",onClick:r,"aria-label":"Collapse sidebar",children:t.jsx(Y,{fontSize:"small"})})]})}function Rt({isCollapsed:e}){const n=Oe().pathname==="/";return t.jsx(Z,{sx:{py:0},children:t.jsx(be,{icon:t.jsx(St,{fontSize:"small"}),label:"Home",to:"/",selected:n,isCollapsed:e})})}function zt({isCollapsed:e}){const{apiClients:r}=Ve(),n=ce(),{data:o}=Ue({queryKey:["environments"],queryFn:()=>r.environments.listEnvironments()}),s=o?.data??[];return s.length===0?null:t.jsxs(x,{sx:{mt:1},children:[!e&&t.jsx(K,{variant:"caption",sx:{display:"block",px:3,py:1,color:"text.secondary",fontWeight:500,textTransform:"uppercase",fontSize:"0.6875rem",letterSpacing:"0.5px"},children:"Environments"}),t.jsx(Z,{sx:{py:0},children:s.map(a=>{const i=a.name??"";return t.jsx(be,{icon:t.jsx(kt,{fontSize:"small"}),label:i,to:`/${i}`,selected:n.environmentName===i,isCollapsed:e},i)})})]})}function Dt({isCollapsed:e}){const r=[{label:"Malloy Docs",href:"https://docs.malloydata.dev/documentation/",icon:t.jsx(vt,{fontSize:"small"}),external:!0},{label:"Publisher Docs",href:"https://github.com/malloydata/publisher/blob/main/README.md",icon:t.jsx(Pt,{fontSize:"small"}),external:!0},{label:"Publisher API",href:"/api-doc.html",icon:t.jsx(wt,{fontSize:"small"}),external:!1}];return t.jsx(Z,{sx:{py:1},children:r.map(n=>t.jsx(Tt,{label:n.label,href:n.href,icon:n.icon,external:n.external,isCollapsed:e},n.label))})}function be({icon:e,label:r,to:n,selected:o,isCollapsed:s}){const a=J(),i=t.jsxs(pe,{selected:o,onClick:c=>a(n,c),sx:{justifyContent:s?"center":"flex-start",px:s?0:2},children:[t.jsx(ue,{sx:{minWidth:s?0:36,justifyContent:"center",color:o?"text.primary":"text.secondary"},children:e}),!s&&t.jsx(he,{primary:r,primaryTypographyProps:{variant:"body2",sx:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}})]});return s?t.jsx(de,{title:r,placement:"right",children:t.jsx(x,{children:i})}):i}function Tt({label:e,href:r,icon:n,external:o,isCollapsed:s}){const a=t.jsxs(pe,{component:"a",href:r,target:o?"_blank":void 0,rel:o?"noopener noreferrer":void 0,sx:{justifyContent:s?"center":"flex-start",px:s?0:2},children:[t.jsx(ue,{sx:{minWidth:s?0:36,justifyContent:"center",color:"text.secondary"},children:n}),!s&&t.jsx(he,{primary:e,primaryTypographyProps:{variant:"body2",sx:{color:"text.secondary",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}})]});return s?t.jsx(de,{title:e,placement:"right",children:t.jsx(x,{children:a})}):a}function Bt({open:e,onClose:r,logoHeader:n}){return t.jsx(yt,{anchor:"left",open:e,onClose:r,ModalProps:{keepMounted:!0},sx:{display:{xs:"block",md:"none"},"& .MuiDrawer-paper":{boxSizing:"border-box",width:260}},children:t.jsx(ye,{isCollapsed:!1,onToggleCollapse:r,logoHeader:n})})}function Ht({headerProps:e}){const r=G(),n=bt(r.breakpoints.up("md")),[o,s]=u.useState(!1),[a,i]=u.useState(!1);return u.useEffect(()=>{n&&o&&s(!1)},[n,o]),t.jsxs(x,{sx:{height:"100dvh",display:"flex",flexDirection:"row",bgcolor:"background.default"},children:[n&&t.jsx(ye,{isCollapsed:a,onToggleCollapse:()=>i(c=>!c),logoHeader:e?.logoHeader}),t.jsxs(x,{component:"main",sx:{flex:1,display:"flex",flexDirection:"column",minWidth:0},children:[t.jsxs(x,{sx:{flexShrink:0,display:"flex",alignItems:"center",justifyContent:"space-between",height:Qe.headerHeight,px:{xs:1,md:3},backgroundColor:"background.default"},children:[t.jsx(x,{sx:{display:{xs:"flex",md:"none"},alignItems:"center",mr:1},children:t.jsx(X,{size:"small",onClick:()=>s(!0),"aria-label":"Open navigation",children:t.jsx(Y,{fontSize:"small"})})}),t.jsx(x,{sx:{flex:1,minWidth:0,display:"flex",alignItems:"center"},children:t.jsx(Ct,{})}),t.jsx(x,{id:"header-actions-portal",sx:{display:"flex",alignItems:"center",flexShrink:0,gap:1},children:e?.endCap})]}),t.jsx(x,{sx:{flex:1,overflow:"auto",minWidth:320,minHeight:0},children:t.jsx(u.Suspense,{fallback:t.jsx(Xe,{}),children:t.jsx(Fe,{})})})]}),t.jsx(Bt,{open:o,onClose:()=>s(!1),logoHeader:e?.logoHeader})]})}export{Ht as default};
@@ -0,0 +1 @@
1
+ import{F as t,j as e,_ as m,G as r,$ as x,a0 as o}from"./index-BMViiwtJ.js";function l(){const n=t(),a=n["*"];if(!n.environmentName)return e.jsx("div",{children:e.jsx("h2",{children:"Missing environment name"})});if(!n.packageName)return e.jsx("div",{children:e.jsx("h2",{children:"Missing package name"})});const i=m({environmentName:n.environmentName,packageName:n.packageName,modelPath:a}),s={p:3,maxWidth:1200,mx:"auto"};return a?.endsWith(".malloy")?e.jsx(r,{sx:s,children:e.jsx(x,{resourceUri:i,runOnDemand:!0,maxResultSize:512*1024})}):a?.endsWith(".malloynb")?e.jsx(r,{sx:s,children:e.jsx(o,{resourceUri:i,maxResultSize:1024*1024})}):e.jsx(r,{sx:s,children:e.jsxs("h2",{children:["Unrecognized file type: ",a]})})}export{l as default};
@@ -0,0 +1 @@
1
+ import{F as r,S as t,j as e,_ as c,a1 as o}from"./index-BMViiwtJ.js";function m(){const{environmentName:a,packageName:n}=r(),s=t();if(a)if(n){const i=c({environmentName:a,packageName:n});return e.jsx(o,{onClickPackageFile:s,resourceUri:i})}else return e.jsx("div",{children:e.jsx("h2",{children:"Missing package name"})});else return e.jsx("div",{children:e.jsx("h2",{children:"Missing environment name"})})}export{m as default};
@@ -0,0 +1 @@
1
+ import{a3 as o,j as r,a4 as s,a5 as n,G as t,T as a}from"./index-BMViiwtJ.js";function x(){const e=o();return console.error(e),r.jsx(s,{maxWidth:"lg",component:"main",sx:{display:"flex",flexDirection:"column",my:2,gap:0},children:r.jsxs(n,{sx:{m:"auto",flexDirection:"column"},children:[r.jsx(t,{sx:{height:"300px"}}),r.jsx("img",{src:"/error.png"}),r.jsx(a,{variant:"subtitle1",children:"An unexpected error occurred"})]})})}export{x as default};
@@ -0,0 +1 @@
1
+ import{F as o,j as e,_ as t,a6 as c}from"./index-BMViiwtJ.js";function l(){const{workspace:r,workbookPath:s,environmentName:i,packageName:n}=o();if(r)if(s)if(i)if(n){const a=t({environmentName:i,packageName:n});return e.jsx(c,{workbookPath:{path:s,workspace:r},resourceUri:a},`${s}`)}else return e.jsx("div",{children:e.jsx("h2",{children:"Missing package name"})});else return e.jsx("div",{children:e.jsx("h2",{children:"Missing environment name"})});else return e.jsx("div",{children:e.jsx("h2",{children:"Missing workbook path"})});else return e.jsx("div",{children:e.jsx("h2",{children:"Missing workspace"})})}export{l as default};