@malloydata/malloyyo 0.2.30 → 0.2.32

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.
@@ -0,0 +1,45 @@
1
+ // Copyright (c) The Malloy Foundation
2
+ // SPDX-License-Identifier: MIT
3
+ //
4
+ // malloy-config.json can hold secrets by reference: `"password": { "env": "PG_PW" }`.
5
+ // Malloy resolves an UNSET reference to empty rather than failing, so the symptom
6
+ // is a baffling connection error — "connect ECONNREFUSED", "password
7
+ // authentication failed" — that never mentions the variable. Both the CLI (this
8
+ // shell) and the push route (that deployment) check for it and say the name.
9
+
10
+ /** `{"env": "NAME"}` references in `configJson` with no value in `env`. Deduped. */
11
+ export function missingEnvRefs(
12
+ configJson: string | undefined,
13
+ env: Record<string, string | undefined> = process.env,
14
+ ): string[] {
15
+ if (!configJson) return [];
16
+ let parsed: unknown;
17
+ try {
18
+ parsed = JSON.parse(configJson);
19
+ } catch {
20
+ return []; // Malloy reports the bad JSON itself.
21
+ }
22
+ const missing = new Set<string>();
23
+ const walk = (node: unknown): void => {
24
+ if (Array.isArray(node)) return void node.forEach(walk);
25
+ if (typeof node !== "object" || node === null) return;
26
+ const rec = node as Record<string, unknown>;
27
+ if (typeof rec.env === "string" && !env[rec.env]) missing.add(rec.env);
28
+ for (const v of Object.values(rec)) walk(v);
29
+ };
30
+ walk(parsed);
31
+ return [...missing];
32
+ }
33
+
34
+ /** One-line-per-var explanation, or "" when nothing is missing. `where` names
35
+ the environment the check ran against ("this shell", a server URL). */
36
+ export function missingEnvHint(missing: string[], where: string): string {
37
+ if (missing.length === 0) return "";
38
+ const vars = missing.map((v) => `$${v}`).join(", ");
39
+ const isAre = missing.length > 1 ? "are" : "is";
40
+ return (
41
+ `\n malloy-config.json references ${vars}, which ${isAre} NOT set on ${where}.` +
42
+ `\n Malloy reads an unset reference as an empty value, which usually shows up as` +
43
+ `\n the connection error above.`
44
+ );
45
+ }
@@ -0,0 +1,25 @@
1
+ // Embedding JSON in an inline <script>, in ONE place.
2
+ //
3
+ // `JSON.stringify` is NOT sufficient here and the failure is not obvious: a
4
+ // script element's content is RAW TEXT terminated by the literal `</script`,
5
+ // regardless of the element's `type`. So a value containing
6
+ // `</script><script>…` closes the block and the rest is parsed as HTML —
7
+ // script execution straight out of a dashboard title, a given label, or a URL
8
+ // parameter. JSON.stringify escapes quotes and backslashes; it does not escape
9
+ // `<`. The hosted app hit exactly this (src/lib/dashboards/frame-html.ts); the
10
+ // three CLI shells emit the same document shape, so they share the same fix.
11
+ //
12
+ // Dependency-free so the Node dev server and the emitted static site can both
13
+ // use it.
14
+
15
+ /** JSON safe to inline inside a `<script>` element. Escapes `<`/`>` so the
16
+ element cannot be terminated early, plus U+2028/U+2029 — legal raw inside a
17
+ JSON string, but literal line terminators in JS source. Every escape is
18
+ inside a string literal, so `JSON.parse` of the result is unchanged. */
19
+ export function safeJson(value: unknown): string {
20
+ return JSON.stringify(value)
21
+ .replace(/</g, "\\u003c")
22
+ .replace(/>/g, "\\u003e")
23
+ .replace(/\u2028/g, "\\u2028")
24
+ .replace(/\u2029/g, "\\u2029");
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloyyo",
3
- "version": "0.2.30",
3
+ "version": "0.2.32",
4
4
  "description": "Publish Malloy models to a Malloyyo instance",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "scripts": {
25
25
  "build:engine": "cd ../mcp-engine && npm run build",
26
- "build": "npm run build:engine && esbuild src/index.ts --bundle --platform=node --format=esm --external:commander --external:esbuild --external:@malloydata/* --external:@modelcontextprotocol/* --outfile=dist/index.js && node scripts/copy-frame-src.mjs",
26
+ "build": "npm run build:engine && esbuild src/index.ts --bundle --platform=node --format=esm --external:commander --external:esbuild --external:@malloydata/* --external:@modelcontextprotocol/* --external:@inquirer/* --outfile=dist/index.js && node scripts/copy-frame-src.mjs",
27
27
  "dev": "tsx src/index.ts",
28
28
  "typecheck": "tsc --noEmit",
29
29
  "pretest": "npm run build",
@@ -33,6 +33,7 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@duckdb/duckdb-wasm": "1.33.1-dev45.0",
36
+ "@inquirer/password": "^5.1.1",
36
37
  "@malloydata/db-duckdb": "^0.0.430",
37
38
  "@malloydata/malloy": "^0.0.430",
38
39
  "@malloydata/malloy-connections": "^0.0.430",