@malloy-publisher/server 0.0.168 → 0.0.170

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@malloy-publisher/server",
3
3
  "description": "Malloy Publisher Server",
4
- "version": "0.0.168",
4
+ "version": "0.0.170",
5
5
  "main": "dist/server.js",
6
6
  "bin": {
7
7
  "malloy-publisher": "dist/server.js"
@@ -30,15 +30,15 @@
30
30
  "dependencies": {
31
31
  "@aws-sdk/client-s3": "^3.958.0",
32
32
  "@google-cloud/storage": "^7.16.0",
33
- "@malloydata/db-bigquery": "^0.0.333",
34
- "@malloydata/db-duckdb": "^0.0.333",
35
- "@malloydata/db-mysql": "^0.0.333",
36
- "@malloydata/db-postgres": "^0.0.333",
37
- "@malloydata/db-snowflake": "^0.0.333",
38
- "@malloydata/db-trino": "^0.0.333",
39
- "@malloydata/malloy": "^0.0.333",
40
- "@malloydata/malloy-sql": "^0.0.333",
41
- "@malloydata/render": "^0.0.333",
33
+ "@malloydata/db-bigquery": "^0.0.358",
34
+ "@malloydata/db-duckdb": "^0.0.358",
35
+ "@malloydata/db-mysql": "^0.0.358",
36
+ "@malloydata/db-postgres": "^0.0.358",
37
+ "@malloydata/db-snowflake": "^0.0.358",
38
+ "@malloydata/db-trino": "^0.0.358",
39
+ "@malloydata/malloy": "^0.0.358",
40
+ "@malloydata/malloy-sql": "^0.0.358",
41
+ "@malloydata/render-validator": "^0.0.358",
42
42
  "@modelcontextprotocol/sdk": "^1.13.2",
43
43
  "@opentelemetry/api": "^1.9.0",
44
44
  "@opentelemetry/auto-instrumentations-node": "^0.57.0",
@@ -1,3 +1,4 @@
1
+ import { validateRenderTags } from "@malloydata/render-validator";
1
2
  import { components } from "../api";
2
3
  import { API_PREFIX } from "../constants";
3
4
  import { ModelNotFoundError } from "../errors";
@@ -41,11 +42,13 @@ export class QueryController {
41
42
  queryName,
42
43
  query,
43
44
  );
45
+ const renderLogs = validateRenderTags(result);
44
46
  return {
45
47
  result: compactJson
46
48
  ? JSON.stringify(compactResult, bigIntReplacer)
47
49
  : JSON.stringify(result),
48
50
  resource: `${API_PREFIX}/projects/${projectName}/packages/${packageName}/models/${modelPath}/query`,
51
+ renderLogs: renderLogs.length > 0 ? renderLogs : undefined,
49
52
  } as ApiQuery;
50
53
  }
51
54
  }
@@ -121,8 +121,11 @@ export function registerExecuteQueryTool(
121
121
  undefined,
122
122
  query,
123
123
  );
124
+ const { validateRenderTags } = await import(
125
+ "@malloydata/render-validator"
126
+ );
127
+ const renderLogs = validateRenderTags(result);
124
128
 
125
- // --- Format Success Response (Duplicated for now, could refactor) ---
126
129
  const baseUriComponents = {
127
130
  project: projectName,
128
131
  package: packageName,
@@ -131,29 +134,43 @@ export function registerExecuteQueryTool(
131
134
  };
132
135
  const resultUri = buildMalloyUri(baseUriComponents, "result");
133
136
  const resultString = JSON.stringify(result, null, 2);
134
- return {
135
- isError: false,
136
- content: [
137
- {
138
- type: "resource",
139
- resource: {
140
- type: "application/json",
141
- uri: resultUri,
142
- text: resultString,
143
- },
137
+
138
+ const content = [
139
+ {
140
+ type: "resource" as const,
141
+ resource: {
142
+ type: "application/json",
143
+ uri: resultUri,
144
+ text: resultString,
144
145
  },
145
- ],
146
- };
146
+ },
147
+ ];
148
+
149
+ if (renderLogs.length > 0) {
150
+ return {
151
+ isError: false,
152
+ content: [
153
+ ...content,
154
+ {
155
+ type: "text" as const,
156
+ text: `Render tag warnings:\n${JSON.stringify(renderLogs, null, 2)}`,
157
+ },
158
+ ],
159
+ };
160
+ }
161
+
162
+ return { isError: false, content };
147
163
  } else if (queryName) {
148
- // Otherwise, use sourceName/queryName in 1st/2nd args
149
164
  const { result } = await model.getQueryResults(
150
165
  sourceName,
151
166
  queryName,
152
167
  undefined,
153
168
  );
169
+ const { validateRenderTags } = await import(
170
+ "@malloydata/render-validator"
171
+ );
172
+ const renderLogs = validateRenderTags(result);
154
173
 
155
- // --- Format Success Response ---
156
- // Use the helper function to build valid URIs
157
174
  const baseUriComponents = {
158
175
  project: projectName,
159
176
  package: packageName,
@@ -161,22 +178,33 @@ export function registerExecuteQueryTool(
161
178
  resourceName: modelPath,
162
179
  };
163
180
  const resultUri = buildMalloyUri(baseUriComponents, "result");
164
-
165
181
  const resultString = JSON.stringify(result, null, 2);
166
182
 
167
- return {
168
- isError: false,
169
- content: [
170
- {
171
- type: "resource",
172
- resource: {
173
- type: "application/json",
174
- uri: resultUri,
175
- text: resultString,
176
- },
183
+ const content = [
184
+ {
185
+ type: "resource" as const,
186
+ resource: {
187
+ type: "application/json",
188
+ uri: resultUri,
189
+ text: resultString,
177
190
  },
178
- ],
179
- };
191
+ },
192
+ ];
193
+
194
+ if (renderLogs.length > 0) {
195
+ return {
196
+ isError: false,
197
+ content: [
198
+ ...content,
199
+ {
200
+ type: "text" as const,
201
+ text: `Render tag warnings:\n${JSON.stringify(renderLogs, null, 2)}`,
202
+ },
203
+ ],
204
+ };
205
+ }
206
+
207
+ return { isError: false, content };
180
208
  }
181
209
 
182
210
  // If execution reaches this point, something has gone wrong with
@@ -10,7 +10,7 @@ import {
10
10
  modelDefToModelInfo,
11
11
  ModelMaterializer,
12
12
  NamedModelObject,
13
- NamedQuery,
13
+ NamedQueryDef,
14
14
  QueryData,
15
15
  QueryMaterializer,
16
16
  Runtime,
@@ -532,7 +532,7 @@ export class Model {
532
532
  ROW_LIMIT;
533
533
  const result = await cell.runnable.run({ rowLimit });
534
534
  const query = (await cell.runnable.getPreparedQuery())._query;
535
- queryName = (query as NamedQuery).as || query.name;
535
+ queryName = (query as NamedQueryDef).as || query.name;
536
536
  queryResult =
537
537
  result?._queryResult &&
538
538
  this.modelInfo &&
@@ -621,11 +621,12 @@ export class Model {
621
621
  modelPath: string,
622
622
  modelDef: ModelDef,
623
623
  ): ApiQuery[] {
624
- const isNamedQuery = (object: NamedModelObject): object is NamedQuery =>
625
- object.type === "query";
624
+ const isNamedQuery = (
625
+ object: NamedModelObject,
626
+ ): object is NamedQueryDef => object.type === "query";
626
627
  return Object.values(modelDef.contents)
627
628
  .filter(isNamedQuery)
628
- .map((queryObj: NamedQuery) => ({
629
+ .map((queryObj: NamedQueryDef) => ({
629
630
  name: queryObj.as || queryObj.name,
630
631
  // What to do when the source is not a string?
631
632
  sourceName:
@@ -633,8 +634,10 @@ export class Model {
633
634
  ? queryObj.structRef
634
635
  : undefined,
635
636
  annotations: queryObj?.annotation?.blockNotes
636
- ?.filter((note) => note.at.url.includes(modelPath))
637
- .map((note) => note.text),
637
+ ?.filter((note: { at: { url: string } }) =>
638
+ note.at.url.includes(modelPath),
639
+ )
640
+ .map((note: { text: string }) => note.text),
638
641
  }));
639
642
  }
640
643
 
@@ -828,7 +831,7 @@ export class Model {
828
831
  let queryInfo: Malloy.QueryInfo | undefined = undefined;
829
832
  try {
830
833
  const preparedQuery = await runnable.getPreparedQuery();
831
- const query = preparedQuery._query as NamedQuery;
834
+ const query = preparedQuery._query as NamedQueryDef;
832
835
  const queryName = query.as || query.name;
833
836
  const anonymousQuery =
834
837
  currentModelInfo.anonymous_queries[