@malloy-publisher/server 0.9.2 → 0.9.3
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/README.docker.md +14 -0
- package/dist/app/api-doc.yaml +287 -45
- package/dist/app/assets/{EnvironmentPage-B-t_QP32.js → EnvironmentPage-uo3igcP9.js} +1 -1
- package/dist/app/assets/{HomePage-Cpu2zMy-.js → HomePage-0OQVchl4.js} +1 -1
- package/dist/app/assets/MainPage-D4SOACdm.js +1 -0
- package/dist/app/assets/ModelPage-B5CpdEDl.js +2 -0
- package/dist/app/assets/PackagePage-BzUfTQKy.js +1 -0
- package/dist/app/assets/{RenderedResult-CBLHr32C.es-DRr9Gmsz.js → RenderedResult-DwB0-9Yx.es-1MzhmBXH.js} +3 -3
- package/dist/app/assets/{RouteError-mgOkv7XK.js → RouteError-BXcrPjvD.js} +1 -1
- package/dist/app/assets/ThemeEditorPage-FpYg5NPt.js +1 -0
- package/dist/app/assets/ToggleButtonGroup-Vkkjsbxx.js +1 -0
- package/dist/app/assets/documentRoutes-BWHzvbNO.js +1 -0
- package/dist/app/assets/index-BZEvIUf-.js +484 -0
- package/dist/app/assets/index-CprgMbE_.js +1 -0
- package/dist/app/assets/{index-IC0jPCkR.js → index-DFvJYp4Q.js} +7 -7
- package/dist/app/assets/index-NVPzfbUZ.js +1317 -0
- package/dist/app/assets/{index-ireHUsv_.js → index-sKcoT1e_.js} +422 -427
- package/dist/app/assets/index.es-D2Ts8adM.js +195 -0
- package/dist/app/index.html +1 -1
- package/dist/cpufeatures-1yrn0vtw.node +0 -0
- package/dist/package_load_worker.mjs +368 -27
- package/dist/server.mjs +12986 -9250
- package/package.json +15 -15
- package/dist/app/assets/LightMode-DOBl6awB.js +0 -1
- package/dist/app/assets/MainPage-C7ySrclP.js +0 -1
- package/dist/app/assets/ModelPage-D8r_J-N9.js +0 -2
- package/dist/app/assets/PackagePage-CcVFBhnT.js +0 -1
- package/dist/app/assets/ThemeEditorPage-CIPDs2w9.js +0 -1
- package/dist/app/assets/ToggleButtonGroup-CEZThrzh.js +0 -1
- package/dist/app/assets/index-Bg-M8sZz.js +0 -1
- package/dist/app/assets/index-ByieDZlo.js +0 -23
- package/dist/app/assets/index-CGdwupPP.js +0 -457
- package/dist/app/assets/index-CeLTZAFW.js +0 -1322
- package/dist/app/assets/index-DoF8ihra.js +0 -1
- package/dist/app/assets/index.es-6eARPKZf.js +0 -198
- package/dist/sshcrypto-cqb52edz.node +0 -0
package/dist/app/index.html
CHANGED
|
@@ -16,7 +16,7 @@ SPDX-License-Identifier: MIT
|
|
|
16
16
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
|
|
17
17
|
/>
|
|
18
18
|
<title>Malloy Publisher</title>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-BZEvIUf-.js"></script>
|
|
20
20
|
<link rel="stylesheet" crossorigin href="/assets/index-DUqldpo0.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
Binary file
|
|
@@ -13195,7 +13195,7 @@ function toQueryTextProblem(problem) {
|
|
|
13195
13195
|
...problem.at ? { at: { range: problem.at.range } } : {}
|
|
13196
13196
|
};
|
|
13197
13197
|
}
|
|
13198
|
-
var GENERIC_INTERNAL_MESSAGE = "Internal server error.", GENERIC_UPSTREAM_MESSAGE = "Upstream connection error.", MAX_LOGGED_DETAIL_CHARS = 2000, FILESYSTEM_ACCESS_DESCRIPTIONS, NotImplementedError, BadRequestError, InvalidArgumentError, CompileRefusedError, EnvironmentNotFoundError, PackageNotFoundError, ModelNotFoundError, DashboardNotFoundError, ConnectionNotFoundError, TableNotFoundError, ConnectionError, DestinationNotFoundError, ConnectionAuthError, UnsupportedCatalogFormatError, ModelCompilationError, PackageManifestError, MaterializationEligibilityError, PublisherConfigError, ServerConfigurationError, FrozenConfigError, AccessDeniedError, QueryCompileError, NotQueryableError, OffSurfaceError, MaterializationNotFoundError, MaterializationConflictError, WriteConflictError, WriteRolledBackError, WriteVerifyError, InvalidStateTransitionError, ServiceUnavailableError, PayloadTooLargeError, ResponseUnserializableError, QueryTimeoutError;
|
|
13198
|
+
var GENERIC_INTERNAL_MESSAGE = "Internal server error.", GENERIC_UPSTREAM_MESSAGE = "Upstream connection error.", MAX_LOGGED_DETAIL_CHARS = 2000, FILESYSTEM_ACCESS_DESCRIPTIONS, NotImplementedError, BadRequestError, InvalidArgumentError, CompileRefusedError, RenderTagRefusedError, UnparseableTextError, EnvironmentNotFoundError, PackageNotFoundError, ModelNotFoundError, DashboardNotFoundError, ConnectionNotFoundError, TableNotFoundError, ConnectionError, DestinationNotFoundError, ConnectionAuthError, UnsupportedCatalogFormatError, ModelCompilationError, PackageManifestError, MaterializationEligibilityError, PublisherConfigError, ServerConfigurationError, FrozenConfigError, AccessDeniedError, QueryCompileError, NotQueryableError, OffSurfaceError, MaterializationNotFoundError, MaterializationConflictError, WriteConflictError, WriteRolledBackError, WriteVerifyError, InvalidStateTransitionError, ServiceUnavailableError, PayloadTooLargeError, ResponseUnserializableError, QueryTimeoutError;
|
|
13199
13199
|
var init_errors = __esm(() => {
|
|
13200
13200
|
init_constants();
|
|
13201
13201
|
init_logger();
|
|
@@ -13218,6 +13218,15 @@ var init_errors = __esm(() => {
|
|
|
13218
13218
|
};
|
|
13219
13219
|
CompileRefusedError = class CompileRefusedError extends BadRequestError {
|
|
13220
13220
|
};
|
|
13221
|
+
RenderTagRefusedError = class RenderTagRefusedError extends CompileRefusedError {
|
|
13222
|
+
};
|
|
13223
|
+
UnparseableTextError = class UnparseableTextError extends CompileRefusedError {
|
|
13224
|
+
detail;
|
|
13225
|
+
constructor(message, detail) {
|
|
13226
|
+
super(message);
|
|
13227
|
+
this.detail = detail;
|
|
13228
|
+
}
|
|
13229
|
+
};
|
|
13221
13230
|
EnvironmentNotFoundError = class EnvironmentNotFoundError extends Error {
|
|
13222
13231
|
constructor(message) {
|
|
13223
13232
|
super(message);
|
|
@@ -16021,6 +16030,39 @@ function findArtifactLineOutsideBlocks(source, artifactLine) {
|
|
|
16021
16030
|
if (artifactLine.test(trimmed))
|
|
16022
16031
|
return trimmed;
|
|
16023
16032
|
}
|
|
16033
|
+
return lexedArtifactNote(source, lines, artifactLine);
|
|
16034
|
+
}
|
|
16035
|
+
function lexedArtifactNote(source, lines, artifactLine) {
|
|
16036
|
+
if (!lines.some((line) => /\S.*##/.test(line) && !/^\s*##/.test(line))) {
|
|
16037
|
+
return;
|
|
16038
|
+
}
|
|
16039
|
+
const translator = new MalloyTranslator(NOTEBOOK_PARSE_URL, null, {
|
|
16040
|
+
urls: { [NOTEBOOK_PARSE_URL]: source }
|
|
16041
|
+
});
|
|
16042
|
+
const parse = translator.parseStep.step(translator).parse;
|
|
16043
|
+
const stream = parse?.tokenStream;
|
|
16044
|
+
const tokens = stream?.getTokens?.() ?? [];
|
|
16045
|
+
const name = (type) => stream?.tokenSource?.vocabulary?.getSymbolicName(type);
|
|
16046
|
+
const text = (i) => source.slice(tokens[i].startIndex, tokens[i].stopIndex + 1);
|
|
16047
|
+
for (let i = 0;i < tokens.length; i++) {
|
|
16048
|
+
const kind = name(tokens[i].type);
|
|
16049
|
+
if (kind === "DOC_ANNOTATION" && artifactLine.test(text(i))) {
|
|
16050
|
+
return text(i).trim();
|
|
16051
|
+
}
|
|
16052
|
+
if (kind !== "DOC_BLOCK_ANNOTATION_BEGIN")
|
|
16053
|
+
continue;
|
|
16054
|
+
let body = "";
|
|
16055
|
+
let j = i;
|
|
16056
|
+
while (name(tokens[j].type) !== "BLOCK_ANNOTATION_END") {
|
|
16057
|
+
body += text(j);
|
|
16058
|
+
if (++j >= tokens.length || name(tokens[j].type) === "EOF") {
|
|
16059
|
+
return;
|
|
16060
|
+
}
|
|
16061
|
+
}
|
|
16062
|
+
if (artifactLine.test(body))
|
|
16063
|
+
return body;
|
|
16064
|
+
i = j;
|
|
16065
|
+
}
|
|
16024
16066
|
return;
|
|
16025
16067
|
}
|
|
16026
16068
|
function artifactKindOfNotes(notes) {
|
|
@@ -16296,7 +16338,9 @@ ${body}`;
|
|
|
16296
16338
|
codeLine: (codeLineOf(span.startCp, span.stopCp) ?? span.startLine) - span.startLine,
|
|
16297
16339
|
...caption !== undefined && { caption },
|
|
16298
16340
|
startLine: span.startLine,
|
|
16299
|
-
endLine: span.endLine
|
|
16341
|
+
endLine: span.endLine,
|
|
16342
|
+
start: span.start,
|
|
16343
|
+
end: span.end
|
|
16300
16344
|
});
|
|
16301
16345
|
continue;
|
|
16302
16346
|
}
|
|
@@ -16350,7 +16394,7 @@ ${body}`;
|
|
|
16350
16394
|
});
|
|
16351
16395
|
}
|
|
16352
16396
|
const runCount = items.filter((item) => item.kind === "statement" && item.run).length;
|
|
16353
|
-
if (runCount !== modelDef.queryList.length) {
|
|
16397
|
+
if (modelDef && runCount !== modelDef.queryList.length) {
|
|
16354
16398
|
return refuse({
|
|
16355
16399
|
line: 1,
|
|
16356
16400
|
message: `Line 1: the notebook reader found ${runCount} run: statements where Malloy compiled ${modelDef.queryList.length}, so its query cells cannot be matched to their results. Fix: none in the file; report it, since the reader and the compiler disagree.`
|
|
@@ -16365,7 +16409,7 @@ ${body}`;
|
|
|
16365
16409
|
if (item.kind === "statement") {
|
|
16366
16410
|
lineRun = undefined;
|
|
16367
16411
|
const queryIndex = item.run ? runsSeen++ : undefined;
|
|
16368
|
-
|
|
16412
|
+
const pushed = item.run && belowTag ? {
|
|
16369
16413
|
kind: "query",
|
|
16370
16414
|
type: "code",
|
|
16371
16415
|
text: item.text,
|
|
@@ -16394,7 +16438,9 @@ ${body}`;
|
|
|
16394
16438
|
},
|
|
16395
16439
|
startLine: item.startLine,
|
|
16396
16440
|
endLine: item.endLine
|
|
16397
|
-
}
|
|
16441
|
+
};
|
|
16442
|
+
cellOffsets.set(pushed, [item.start, item.end]);
|
|
16443
|
+
cells.push(pushed);
|
|
16398
16444
|
return;
|
|
16399
16445
|
}
|
|
16400
16446
|
const { note } = item;
|
|
@@ -16498,7 +16544,7 @@ function notebookReaderProblem(modelPath, text, modelDef, url) {
|
|
|
16498
16544
|
}
|
|
16499
16545
|
};
|
|
16500
16546
|
}
|
|
16501
|
-
var NOTEBOOKS_DIR = "notebooks", DASHBOARDS_DIR = "dashboards", ARTIFACT_NOTE, ANY_ARTIFACT_NOTE, MARKDOWN_ROUTE = "markdown", attachedNowhereFix = (block) => block ? "write it as a floating `##|(markdown)` block closed by `|##` for prose that stands on its own, or move it directly above the statement it describes." : "write it as a floating `##(markdown)` line for prose that stands on its own, or move it directly above the statement it describes.", isRuleNode = (node) => node !== undefined && node.ruleIndex !== undefined && (node.childCount ?? 0) > 0, callAccessor = (node, name) => {
|
|
16547
|
+
var NOTEBOOKS_DIR = "notebooks", DASHBOARDS_DIR = "dashboards", ARTIFACT_NOTE, ANY_ARTIFACT_NOTE, MARKDOWN_ROUTE = "markdown", attachedNowhereFix = (block) => block ? "write it as a floating `##|(markdown)` block closed by `|##` for prose that stands on its own, or move it directly above the statement it describes." : "write it as a floating `##(markdown)` line for prose that stands on its own, or move it directly above the statement it describes.", cellOffsets, isRuleNode = (node) => node !== undefined && node.ruleIndex !== undefined && (node.childCount ?? 0) > 0, callAccessor = (node, name) => {
|
|
16502
16548
|
const accessor = node[name];
|
|
16503
16549
|
return typeof accessor === "function" ? accessor.call(node) : undefined;
|
|
16504
16550
|
}, STATEMENT_ACCESSORS, NOTEBOOK_PARSE_URL = "file:///publisher-notebook-reader/notebook.malloy", NOTE_TOKENS, TEXT_BLOCK_NAME;
|
|
@@ -16563,6 +16609,7 @@ var init_notebook = __esm(() => {
|
|
|
16563
16609
|
}
|
|
16564
16610
|
};
|
|
16565
16611
|
ANY_ARTIFACT_NOTE = /^#{1,2}\|?(?=[ \t\r\n])(?:[^"'\\]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')*?(?<![\w\u00C0-\u024F\u1E00-\u1EFF.$-])artifact(?![\w\u00C0-\u024F\u1E00-\u1EFF])/;
|
|
16612
|
+
cellOffsets = new WeakMap;
|
|
16566
16613
|
STATEMENT_ACCESSORS = [
|
|
16567
16614
|
["runStatement", "run"],
|
|
16568
16615
|
["docAnnotations", "notes"],
|
|
@@ -23267,6 +23314,7 @@ function malloyGivenToApi(given) {
|
|
|
23267
23314
|
type: renderedType,
|
|
23268
23315
|
annotations: allNotes.filter((note) => !isReservedRoute(note.route) && note.route !== MARKDOWN_ROUTE).map((note) => note.text),
|
|
23269
23316
|
...readGivenControlSpec(allNotes.map((note) => note.text)),
|
|
23317
|
+
...allNotes.some((note) => note.route === "secure") && { secure: true },
|
|
23270
23318
|
default: given._internal?.defaultText
|
|
23271
23319
|
};
|
|
23272
23320
|
}
|
|
@@ -23443,6 +23491,13 @@ function readArtifactTag(tag, declaredType) {
|
|
|
23443
23491
|
autorun
|
|
23444
23492
|
};
|
|
23445
23493
|
}
|
|
23494
|
+
function readDocumentTileExpressions(notes) {
|
|
23495
|
+
const tag = motlyTag(notes);
|
|
23496
|
+
const composite = tag ? readArtifactTag(tag, () => {
|
|
23497
|
+
return;
|
|
23498
|
+
}) : undefined;
|
|
23499
|
+
return (composite?.tiles ?? []).flatMap((entry) => entry.kind === "text" ? [] : [entry.expression]);
|
|
23500
|
+
}
|
|
23446
23501
|
function readTextBlocks(notes) {
|
|
23447
23502
|
return notes.flatMap((note) => {
|
|
23448
23503
|
const newline = note.indexOf(`
|
|
@@ -23626,6 +23681,9 @@ function givenSpec(declaration, facts) {
|
|
|
23626
23681
|
type: declaration.type,
|
|
23627
23682
|
default: declaration.type.startsWith("filter<") && declaration.default !== undefined ? unwrapFilterLiteral(declaration.default) : declaration.default,
|
|
23628
23683
|
annotations: declaration.annotations.filter((text) => /^##?\(/.test(text) && !isMarkdownNote(text)),
|
|
23684
|
+
...declaration.annotations.some((text) => /^#\(secure\)/.test(text)) && {
|
|
23685
|
+
secure: true
|
|
23686
|
+
},
|
|
23629
23687
|
...control
|
|
23630
23688
|
};
|
|
23631
23689
|
}
|
|
@@ -23634,7 +23692,7 @@ function factsCarryArtifactTag(facts) {
|
|
|
23634
23692
|
return true;
|
|
23635
23693
|
return facts.queries.some((query) => Boolean(motlyTag(query.annotations)?.tag("artifact")));
|
|
23636
23694
|
}
|
|
23637
|
-
function buildDashboardManifest(facts) {
|
|
23695
|
+
function buildDashboardManifest(facts, options) {
|
|
23638
23696
|
const name = dashboardSlug(facts.modelPath);
|
|
23639
23697
|
const base = {
|
|
23640
23698
|
name,
|
|
@@ -23657,6 +23715,9 @@ function buildDashboardManifest(facts) {
|
|
|
23657
23715
|
};
|
|
23658
23716
|
}
|
|
23659
23717
|
const query = entry.expression;
|
|
23718
|
+
if (options?.restrictedTiles?.has(normalizeTileExpression(query))) {
|
|
23719
|
+
return { kind: "query", query, restricted: true };
|
|
23720
|
+
}
|
|
23660
23721
|
const givenNames = resolveTileGivens(query, facts);
|
|
23661
23722
|
const layout = resolveTileLayout(query, facts);
|
|
23662
23723
|
return {
|
|
@@ -23666,7 +23727,7 @@ function buildDashboardManifest(facts) {
|
|
|
23666
23727
|
...layout
|
|
23667
23728
|
};
|
|
23668
23729
|
});
|
|
23669
|
-
const queries = queryTiles(tiles);
|
|
23730
|
+
const queries = queryTiles(tiles).filter((tile) => !tile.restricted);
|
|
23670
23731
|
const doc = docCommentTitleAndDescription(facts.descriptionNotes ?? facts.modelAnnotations, composite.title);
|
|
23671
23732
|
return {
|
|
23672
23733
|
...base,
|
|
@@ -23959,9 +24020,40 @@ function lintSelfDrills(facts) {
|
|
|
23959
24020
|
}
|
|
23960
24021
|
return Array.from(findings.values());
|
|
23961
24022
|
}
|
|
24023
|
+
async function compileTileGivens(tiles, materializer, fallbackRegistry, gatesOf, skip, onPrepared, onCompileError) {
|
|
24024
|
+
const compiled = new Map;
|
|
24025
|
+
for (const tile of tiles) {
|
|
24026
|
+
const key = normalizeTileExpression(tile);
|
|
24027
|
+
if (compiled.has(key) || skip?.has(key))
|
|
24028
|
+
continue;
|
|
24029
|
+
let prepared;
|
|
24030
|
+
try {
|
|
24031
|
+
prepared = await materializer.loadQuery(`run: ${tile}`).getPreparedQuery();
|
|
24032
|
+
} catch (error) {
|
|
24033
|
+
onCompileError?.(tile, error);
|
|
24034
|
+
continue;
|
|
24035
|
+
}
|
|
24036
|
+
await onPrepared?.(tile, prepared);
|
|
24037
|
+
const usage = prepared._query?.givenUsage;
|
|
24038
|
+
if (!usage)
|
|
24039
|
+
continue;
|
|
24040
|
+
const registry = prepared._modelDef?.givens ?? fallbackRegistry ?? {};
|
|
24041
|
+
const reads = usage.map((given) => registry[given.id]?.name).filter((name) => name !== undefined);
|
|
24042
|
+
const target = prepared._query?.structRef;
|
|
24043
|
+
const sourceName = typeof target === "string" ? target : target?.as || target?.name;
|
|
24044
|
+
const gateReads = new Set;
|
|
24045
|
+
for (const expr of sourceName ? gatesOf(sourceName) ?? [] : []) {
|
|
24046
|
+
for (const name of referencedGivenNames(expr))
|
|
24047
|
+
gateReads.add(name);
|
|
24048
|
+
}
|
|
24049
|
+
compiled.set(key, { reads, gateReads: Array.from(gateReads) });
|
|
24050
|
+
}
|
|
24051
|
+
return compiled;
|
|
24052
|
+
}
|
|
23962
24053
|
var MAX_BUILDER_COLUMNS = 24, COMPONENT_FILE_SUFFIXES, MODEL_FILE_SUFFIX2 = ".malloy", PUBLISHER_OWNED_TAGS, RENDERER_CHILD_TAGS, UNKNOWN_RENDER_TAG, COMPOSITE_ARTIFACT_PROPERTIES, QUERY_ARTIFACT_PROPERTIES, ARTIFACT_PROPERTY_REPLACEMENTS, NAME_THE_TILES = `Name the views to show: tiles=["source -> view", …].`;
|
|
23963
24054
|
var init_dashboard = __esm(() => {
|
|
23964
24055
|
init_annotations();
|
|
24056
|
+
init_authorize();
|
|
23965
24057
|
init_notebook();
|
|
23966
24058
|
init_given();
|
|
23967
24059
|
init_motly();
|
|
@@ -24414,11 +24506,11 @@ var init_source_extraction = __esm(() => {
|
|
|
24414
24506
|
});
|
|
24415
24507
|
|
|
24416
24508
|
// src/utils.ts
|
|
24417
|
-
import * as
|
|
24418
|
-
import * as
|
|
24509
|
+
import * as fs2 from "fs";
|
|
24510
|
+
import * as path2 from "path";
|
|
24419
24511
|
import { fileURLToPath } from "url";
|
|
24420
24512
|
function ignoreDotfiles(file) {
|
|
24421
|
-
return
|
|
24513
|
+
return path2.basename(file).startsWith(".");
|
|
24422
24514
|
}
|
|
24423
24515
|
function errMessage(err) {
|
|
24424
24516
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -24427,11 +24519,11 @@ var URL_READER;
|
|
|
24427
24519
|
var init_utils = __esm(() => {
|
|
24428
24520
|
URL_READER = {
|
|
24429
24521
|
readURL: (url) => {
|
|
24430
|
-
let
|
|
24522
|
+
let path3 = url.toString();
|
|
24431
24523
|
if (url.protocol == "file:") {
|
|
24432
|
-
|
|
24524
|
+
path3 = fileURLToPath(url);
|
|
24433
24525
|
}
|
|
24434
|
-
return
|
|
24526
|
+
return fs2.promises.readFile(path3, "utf8");
|
|
24435
24527
|
}
|
|
24436
24528
|
};
|
|
24437
24529
|
});
|
|
@@ -24457,8 +24549,8 @@ import {
|
|
|
24457
24549
|
MalloySQLParser,
|
|
24458
24550
|
MalloySQLStatementType
|
|
24459
24551
|
} from "@malloydata/malloy-sql";
|
|
24460
|
-
import * as
|
|
24461
|
-
import * as
|
|
24552
|
+
import * as fs3 from "fs";
|
|
24553
|
+
import * as path3 from "path";
|
|
24462
24554
|
import { parentPort, threadId } from "node:worker_threads";
|
|
24463
24555
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
24464
24556
|
|
|
@@ -24645,6 +24737,254 @@ var EXPLORES_EMPTY_SUPPRESSES_CONVENTION = `"explores" in publisher.json is depr
|
|
|
24645
24737
|
var EXPLORES_EMPTY_IS_UNCURATED = `"explores": [] in publisher.json does nothing. Fix: delete it.`;
|
|
24646
24738
|
var QUERYABLE_SOURCES_DEPRECATION = `"queryableSources" in publisher.json does nothing. Fix: delete it.`;
|
|
24647
24739
|
|
|
24740
|
+
// src/service/package_retrieval.ts
|
|
24741
|
+
init_errors();
|
|
24742
|
+
import { createHash } from "crypto";
|
|
24743
|
+
import * as fs from "fs";
|
|
24744
|
+
import * as path from "path";
|
|
24745
|
+
var PACKAGE_REPRESENTATIONS = ["single", "facets"];
|
|
24746
|
+
var KEYPHRASE_MODES = ["auto", "never", "always"];
|
|
24747
|
+
var REFINE_LEVEL_NAMES = ["LOW", "MEDIUM", "HIGH"];
|
|
24748
|
+
var DEFAULT_RERANK_TOP_SOURCES = 8;
|
|
24749
|
+
var DEFAULT_REFINE_MIN_LEVEL = "MEDIUM";
|
|
24750
|
+
var RETRIEVAL_KEYS = [
|
|
24751
|
+
"representation",
|
|
24752
|
+
"keyphrases",
|
|
24753
|
+
"refine",
|
|
24754
|
+
"rerank",
|
|
24755
|
+
"sourceMatch",
|
|
24756
|
+
"sourceSummary",
|
|
24757
|
+
"prompts"
|
|
24758
|
+
];
|
|
24759
|
+
var PROMPT_KEYS = [
|
|
24760
|
+
"keyphrase",
|
|
24761
|
+
"refine",
|
|
24762
|
+
"rerank",
|
|
24763
|
+
"sourceMatch",
|
|
24764
|
+
"sourceSummary"
|
|
24765
|
+
];
|
|
24766
|
+
var REFINE_KEYS = ["enabled", "minLevel"];
|
|
24767
|
+
var RERANK_KEYS = ["enabled", "topSources"];
|
|
24768
|
+
var SOURCE_MATCH_KEYS = ["enabled"];
|
|
24769
|
+
var SOURCE_SUMMARY_KEYS = ["enabled"];
|
|
24770
|
+
var DEFAULT_PACKAGE_RETRIEVAL = {
|
|
24771
|
+
representation: "single",
|
|
24772
|
+
keyphrases: "auto",
|
|
24773
|
+
prompts: {}
|
|
24774
|
+
};
|
|
24775
|
+
function refineSettingsOf(retrieval) {
|
|
24776
|
+
return retrieval.refine ?? {
|
|
24777
|
+
enabled: "auto",
|
|
24778
|
+
minLevel: DEFAULT_REFINE_MIN_LEVEL
|
|
24779
|
+
};
|
|
24780
|
+
}
|
|
24781
|
+
function rerankSettingsOf(retrieval) {
|
|
24782
|
+
return retrieval.rerank ?? {
|
|
24783
|
+
enabled: "auto",
|
|
24784
|
+
topSources: DEFAULT_RERANK_TOP_SOURCES
|
|
24785
|
+
};
|
|
24786
|
+
}
|
|
24787
|
+
function sourceMatchSettingsOf(retrieval) {
|
|
24788
|
+
return retrieval.sourceMatch ?? { enabled: "auto" };
|
|
24789
|
+
}
|
|
24790
|
+
function sourceSummarySettingsOf(retrieval) {
|
|
24791
|
+
return retrieval.sourceSummary ?? { enabled: "auto" };
|
|
24792
|
+
}
|
|
24793
|
+
function fail(message) {
|
|
24794
|
+
throw new PackageManifestError(message);
|
|
24795
|
+
}
|
|
24796
|
+
function describe(value) {
|
|
24797
|
+
return JSON.stringify(value) ?? "nothing";
|
|
24798
|
+
}
|
|
24799
|
+
function stepsOutside(within) {
|
|
24800
|
+
return within === ".." || within.startsWith(`..${path.sep}`) || path.isAbsolute(within);
|
|
24801
|
+
}
|
|
24802
|
+
function resolvePromptPath(packageRoot, rel, promptKey = "keyphrase") {
|
|
24803
|
+
const key = `retrieval.prompts.${promptKey}`;
|
|
24804
|
+
const fix = `Fix: use a path inside the package, e.g. "prompts/${promptKey}.md".`;
|
|
24805
|
+
if (rel.includes("\x00") || path.isAbsolute(rel) || /^[A-Za-z]:[\\/]/.test(rel) || rel.startsWith("\\")) {
|
|
24806
|
+
fail(`Invalid publisher.json ${key}: ${describe(rel)} is an absolute path. ${fix}`);
|
|
24807
|
+
}
|
|
24808
|
+
const root = path.resolve(packageRoot);
|
|
24809
|
+
const resolved = path.resolve(root, rel);
|
|
24810
|
+
const within = path.relative(root, resolved);
|
|
24811
|
+
if (within === "" || stepsOutside(within)) {
|
|
24812
|
+
fail(`Invalid publisher.json ${key}: ${describe(rel)} resolves outside the package directory. ${fix}`);
|
|
24813
|
+
}
|
|
24814
|
+
return resolved;
|
|
24815
|
+
}
|
|
24816
|
+
function objectBlock(raw, key, valid, fix) {
|
|
24817
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
24818
|
+
fail(`Invalid publisher.json ${key}: expected an object, got ${describe(raw)}. Fix: ${fix}`);
|
|
24819
|
+
}
|
|
24820
|
+
const obj = raw;
|
|
24821
|
+
const unknown = Object.keys(obj).filter((k) => !valid.includes(k));
|
|
24822
|
+
if (unknown.length > 0) {
|
|
24823
|
+
fail(`Invalid publisher.json ${key}: unknown key ${unknown.map((k) => `'${k}'`).join(", ")}. ` + `Valid keys: ${valid.join(", ")}.`);
|
|
24824
|
+
}
|
|
24825
|
+
return obj;
|
|
24826
|
+
}
|
|
24827
|
+
function parseEnabled(value, key) {
|
|
24828
|
+
if (value === undefined || value === null)
|
|
24829
|
+
return "auto";
|
|
24830
|
+
if (value === "auto" || value === true || value === false)
|
|
24831
|
+
return value;
|
|
24832
|
+
return fail(`Invalid publisher.json ${key}: expected "auto", true or false, got ${describe(value)}. ` + `Fix: "enabled": "auto" (on when the server has an LLM), true (require one) or false.`);
|
|
24833
|
+
}
|
|
24834
|
+
function parseRefine(raw) {
|
|
24835
|
+
const obj = objectBlock(raw, "retrieval.refine", REFINE_KEYS, `"refine": { "enabled": "auto", "minLevel": "MEDIUM" }`);
|
|
24836
|
+
const minLevel = obj.minLevel ?? DEFAULT_REFINE_MIN_LEVEL;
|
|
24837
|
+
if (typeof minLevel !== "string" || !REFINE_LEVEL_NAMES.includes(minLevel)) {
|
|
24838
|
+
fail(`Invalid publisher.json retrieval.refine.minLevel: expected one of ${REFINE_LEVEL_NAMES.join(", ")}, got ${describe(obj.minLevel)}. ` + `Fix: "minLevel": "MEDIUM" (drop candidates the model rates below it).`);
|
|
24839
|
+
}
|
|
24840
|
+
return {
|
|
24841
|
+
enabled: parseEnabled(obj.enabled, "retrieval.refine.enabled"),
|
|
24842
|
+
minLevel
|
|
24843
|
+
};
|
|
24844
|
+
}
|
|
24845
|
+
function parseRerank(raw) {
|
|
24846
|
+
const obj = objectBlock(raw, "retrieval.rerank", RERANK_KEYS, `"rerank": { "enabled": "auto", "topSources": ${DEFAULT_RERANK_TOP_SOURCES} }`);
|
|
24847
|
+
const top = obj.topSources ?? DEFAULT_RERANK_TOP_SOURCES;
|
|
24848
|
+
if (typeof top !== "number" || !Number.isSafeInteger(top) || top <= 0) {
|
|
24849
|
+
fail(`Invalid publisher.json retrieval.rerank.topSources: expected a positive integer, got ${describe(obj.topSources)}. ` + `Fix: "topSources": ${DEFAULT_RERANK_TOP_SOURCES}`);
|
|
24850
|
+
}
|
|
24851
|
+
return {
|
|
24852
|
+
enabled: parseEnabled(obj.enabled, "retrieval.rerank.enabled"),
|
|
24853
|
+
topSources: top
|
|
24854
|
+
};
|
|
24855
|
+
}
|
|
24856
|
+
function parseSourceMatch(raw) {
|
|
24857
|
+
const obj = objectBlock(raw, "retrieval.sourceMatch", SOURCE_MATCH_KEYS, `"sourceMatch": { "enabled": "auto" }`);
|
|
24858
|
+
return {
|
|
24859
|
+
enabled: parseEnabled(obj.enabled, "retrieval.sourceMatch.enabled")
|
|
24860
|
+
};
|
|
24861
|
+
}
|
|
24862
|
+
function parseSourceSummary(raw) {
|
|
24863
|
+
const obj = objectBlock(raw, "retrieval.sourceSummary", SOURCE_SUMMARY_KEYS, `"sourceSummary": { "enabled": "auto" }`);
|
|
24864
|
+
return {
|
|
24865
|
+
enabled: parseEnabled(obj.enabled, "retrieval.sourceSummary.enabled")
|
|
24866
|
+
};
|
|
24867
|
+
}
|
|
24868
|
+
function parsePackageRetrieval(raw) {
|
|
24869
|
+
if (raw === undefined || raw === null) {
|
|
24870
|
+
return {
|
|
24871
|
+
representation: DEFAULT_PACKAGE_RETRIEVAL.representation,
|
|
24872
|
+
keyphrases: DEFAULT_PACKAGE_RETRIEVAL.keyphrases,
|
|
24873
|
+
promptPaths: {}
|
|
24874
|
+
};
|
|
24875
|
+
}
|
|
24876
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
24877
|
+
fail(`Invalid publisher.json retrieval: expected an object, got ${describe(raw)}. ` + `Fix: "retrieval": { "representation": "single" }`);
|
|
24878
|
+
}
|
|
24879
|
+
const obj = raw;
|
|
24880
|
+
const unknown = Object.keys(obj).filter((k) => !RETRIEVAL_KEYS.includes(k));
|
|
24881
|
+
if (unknown.length > 0) {
|
|
24882
|
+
fail(`Invalid publisher.json retrieval: unknown key ${unknown.map((k) => `'${k}'`).join(", ")}. ` + `Valid keys: ${RETRIEVAL_KEYS.join(", ")}.`);
|
|
24883
|
+
}
|
|
24884
|
+
const representation = obj.representation ?? "single";
|
|
24885
|
+
if (typeof representation !== "string" || !PACKAGE_REPRESENTATIONS.includes(representation)) {
|
|
24886
|
+
fail(`Invalid publisher.json retrieval.representation: expected one of ${PACKAGE_REPRESENTATIONS.join(", ")}, got ${describe(obj.representation)}. ` + `Fix: "representation": "single" (one row per entity) or "facets" (a name row plus doc chunks).`);
|
|
24887
|
+
}
|
|
24888
|
+
const keyphrases = obj.keyphrases ?? "auto";
|
|
24889
|
+
if (typeof keyphrases !== "string" || !KEYPHRASE_MODES.includes(keyphrases)) {
|
|
24890
|
+
fail(`Invalid publisher.json retrieval.keyphrases: expected one of ${KEYPHRASE_MODES.join(", ")}, got ${describe(obj.keyphrases)}. ` + `Fix: "keyphrases": "auto".`);
|
|
24891
|
+
}
|
|
24892
|
+
const refine = obj.refine === undefined || obj.refine === null ? undefined : parseRefine(obj.refine);
|
|
24893
|
+
const rerank = obj.rerank === undefined || obj.rerank === null ? undefined : parseRerank(obj.rerank);
|
|
24894
|
+
const sourceMatch = obj.sourceMatch === undefined || obj.sourceMatch === null ? undefined : parseSourceMatch(obj.sourceMatch);
|
|
24895
|
+
const sourceSummary = obj.sourceSummary === undefined || obj.sourceSummary === null ? undefined : parseSourceSummary(obj.sourceSummary);
|
|
24896
|
+
const promptPaths = {};
|
|
24897
|
+
if (obj.prompts !== undefined && obj.prompts !== null) {
|
|
24898
|
+
if (typeof obj.prompts !== "object" || Array.isArray(obj.prompts)) {
|
|
24899
|
+
fail(`Invalid publisher.json retrieval.prompts: expected an object, got ${describe(obj.prompts)}. ` + `Fix: "prompts": { "keyphrase": "prompts/keyphrase.md" }`);
|
|
24900
|
+
}
|
|
24901
|
+
const prompts = obj.prompts;
|
|
24902
|
+
const badPrompt = Object.keys(prompts).filter((k) => !PROMPT_KEYS.includes(k));
|
|
24903
|
+
if (badPrompt.length > 0) {
|
|
24904
|
+
fail(`Invalid publisher.json retrieval.prompts: unknown key ${badPrompt.map((k) => `'${k}'`).join(", ")}. ` + `Valid keys: ${PROMPT_KEYS.join(", ")}.`);
|
|
24905
|
+
}
|
|
24906
|
+
for (const key of PROMPT_KEYS) {
|
|
24907
|
+
const value = prompts[key];
|
|
24908
|
+
if (value === undefined || value === null)
|
|
24909
|
+
continue;
|
|
24910
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
24911
|
+
fail(`Invalid publisher.json retrieval.prompts.${key}: expected a file path inside the package, got ${describe(value)}. ` + `Fix: "${key}": "prompts/${key}.md"`);
|
|
24912
|
+
}
|
|
24913
|
+
promptPaths[key] = value;
|
|
24914
|
+
}
|
|
24915
|
+
}
|
|
24916
|
+
return {
|
|
24917
|
+
representation,
|
|
24918
|
+
keyphrases,
|
|
24919
|
+
...refine ? { refine } : {},
|
|
24920
|
+
...rerank ? { rerank } : {},
|
|
24921
|
+
...sourceMatch ? { sourceMatch } : {},
|
|
24922
|
+
...sourceSummary ? { sourceSummary } : {},
|
|
24923
|
+
promptPaths
|
|
24924
|
+
};
|
|
24925
|
+
}
|
|
24926
|
+
async function readPromptFile(packageRoot, key, rel) {
|
|
24927
|
+
const file = resolvePromptPath(packageRoot, rel, key);
|
|
24928
|
+
const at = `retrieval.prompts.${key}`;
|
|
24929
|
+
let text;
|
|
24930
|
+
try {
|
|
24931
|
+
const [realRoot, realFile] = await Promise.all([
|
|
24932
|
+
fs.promises.realpath(packageRoot),
|
|
24933
|
+
fs.promises.realpath(file)
|
|
24934
|
+
]);
|
|
24935
|
+
const within = path.relative(realRoot, realFile);
|
|
24936
|
+
if (stepsOutside(within)) {
|
|
24937
|
+
fail(`Invalid publisher.json ${at}: ${describe(rel)} resolves outside the package directory through a link. ` + `Fix: copy the file into the package.`);
|
|
24938
|
+
}
|
|
24939
|
+
text = await fs.promises.readFile(realFile, "utf8");
|
|
24940
|
+
} catch (error) {
|
|
24941
|
+
if (error instanceof PackageManifestError)
|
|
24942
|
+
throw error;
|
|
24943
|
+
return fail(`Invalid publisher.json ${at}: cannot read ${describe(rel)} (${error.message}). ` + `Fix: create the file inside the package or remove the key.`);
|
|
24944
|
+
}
|
|
24945
|
+
if (text.trim() === "") {
|
|
24946
|
+
fail(`Invalid publisher.json ${at}: ${describe(rel)} is empty. ` + `Fix: write the prompt, or remove the key to use the built-in one.`);
|
|
24947
|
+
}
|
|
24948
|
+
return {
|
|
24949
|
+
path: rel,
|
|
24950
|
+
text,
|
|
24951
|
+
hash: createHash("sha256").update(text).digest("hex")
|
|
24952
|
+
};
|
|
24953
|
+
}
|
|
24954
|
+
async function readPackageRetrieval(packageRoot, raw) {
|
|
24955
|
+
const parsed = parsePackageRetrieval(raw);
|
|
24956
|
+
const prompts = {};
|
|
24957
|
+
for (const key of PROMPT_KEYS) {
|
|
24958
|
+
const rel = parsed.promptPaths[key];
|
|
24959
|
+
if (rel !== undefined) {
|
|
24960
|
+
prompts[key] = await readPromptFile(packageRoot, key, rel);
|
|
24961
|
+
}
|
|
24962
|
+
}
|
|
24963
|
+
return {
|
|
24964
|
+
representation: parsed.representation,
|
|
24965
|
+
keyphrases: parsed.keyphrases,
|
|
24966
|
+
...parsed.refine ? { refine: parsed.refine } : {},
|
|
24967
|
+
...parsed.rerank ? { rerank: parsed.rerank } : {},
|
|
24968
|
+
...parsed.sourceMatch ? { sourceMatch: parsed.sourceMatch } : {},
|
|
24969
|
+
...parsed.sourceSummary ? { sourceSummary: parsed.sourceSummary } : {},
|
|
24970
|
+
prompts
|
|
24971
|
+
};
|
|
24972
|
+
}
|
|
24973
|
+
function assertRequiredStagesAvailable(retrieval, llmConfigured) {
|
|
24974
|
+
if (llmConfigured)
|
|
24975
|
+
return;
|
|
24976
|
+
for (const [key, stage] of [
|
|
24977
|
+
["refine", retrieval.refine],
|
|
24978
|
+
["rerank", retrieval.rerank],
|
|
24979
|
+
["sourceMatch", retrieval.sourceMatch],
|
|
24980
|
+
["sourceSummary", retrieval.sourceSummary]
|
|
24981
|
+
]) {
|
|
24982
|
+
if (stage?.enabled === true) {
|
|
24983
|
+
fail(`Invalid publisher.json retrieval.${key}.enabled: true needs an LLM, and this server has none configured. ` + `Fix: set retrieval.llm in publisher.config.json and LLM_API_KEY in the server's environment, ` + `or set "enabled": "auto" (on only when an LLM is configured) or false.`);
|
|
24984
|
+
}
|
|
24985
|
+
}
|
|
24986
|
+
}
|
|
24987
|
+
|
|
24648
24988
|
// src/package_load/package_load_worker.ts
|
|
24649
24989
|
init_source_extraction();
|
|
24650
24990
|
init_given();
|
|
@@ -24704,9 +25044,9 @@ function newRpcId() {
|
|
|
24704
25044
|
}
|
|
24705
25045
|
function callMain(send) {
|
|
24706
25046
|
const requestId = newRpcId();
|
|
24707
|
-
return new Promise((
|
|
25047
|
+
return new Promise((resolve3, reject2) => {
|
|
24708
25048
|
pendingRpc.set(requestId, {
|
|
24709
|
-
resolve: (value) =>
|
|
25049
|
+
resolve: (value) => resolve3(value),
|
|
24710
25050
|
reject: reject2
|
|
24711
25051
|
});
|
|
24712
25052
|
send(requestId);
|
|
@@ -24826,10 +25166,10 @@ function makeWorkerUrlReader(job) {
|
|
|
24826
25166
|
readURL: async (url) => {
|
|
24827
25167
|
if (url.protocol === "file:") {
|
|
24828
25168
|
const filePath = fileURLToPath2(url);
|
|
24829
|
-
if (job.replacement &&
|
|
25169
|
+
if (job.replacement && path3.resolve(filePath) === path3.resolve(job.packagePath, job.replacement.modelPath)) {
|
|
24830
25170
|
return job.replacement.source;
|
|
24831
25171
|
}
|
|
24832
|
-
return
|
|
25172
|
+
return fs3.promises.readFile(filePath, "utf8");
|
|
24833
25173
|
}
|
|
24834
25174
|
const response = await callMain((requestId) => {
|
|
24835
25175
|
const req = {
|
|
@@ -24879,8 +25219,8 @@ function buildWorkerMalloyConfig(job) {
|
|
|
24879
25219
|
return config;
|
|
24880
25220
|
}
|
|
24881
25221
|
async function readPackageMetadata(packagePath, modelPaths) {
|
|
24882
|
-
const manifestPath =
|
|
24883
|
-
const contents = await
|
|
25222
|
+
const manifestPath = path3.join(packagePath, PACKAGE_MANIFEST_NAME);
|
|
25223
|
+
const contents = await fs3.promises.readFile(manifestPath, "utf8");
|
|
24884
25224
|
let parsed;
|
|
24885
25225
|
try {
|
|
24886
25226
|
parsed = JSON.parse(contents);
|
|
@@ -24911,12 +25251,13 @@ async function readPackageMetadata(packagePath, modelPaths) {
|
|
|
24911
25251
|
manifestLocation: typeof parsed.manifestLocation === "string" ? parsed.manifestLocation : null,
|
|
24912
25252
|
materialization: materializationWithQueryMetadata(parsePackageMaterialization(parsed.materialization), queryMetadata.queryMetadata),
|
|
24913
25253
|
scope: scope.scope,
|
|
24914
|
-
manifestWarnings: manifestWarnings.length > 0 ? manifestWarnings : undefined
|
|
25254
|
+
manifestWarnings: manifestWarnings.length > 0 ? manifestWarnings : undefined,
|
|
25255
|
+
retrieval: await readPackageRetrieval(packagePath, parsed.retrieval)
|
|
24915
25256
|
};
|
|
24916
25257
|
}
|
|
24917
25258
|
async function listPackageFiles(packagePath) {
|
|
24918
25259
|
const files = await import_recursive_readdir.default(packagePath, [ignoreDotfiles]);
|
|
24919
|
-
return files.map((full) =>
|
|
25260
|
+
return files.map((full) => path3.relative(packagePath, full).replace(/\\/g, "/")).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
24920
25261
|
}
|
|
24921
25262
|
function filterModelPaths(allRelative) {
|
|
24922
25263
|
return allRelative.filter((p) => p.endsWith(MODEL_FILE_SUFFIX) || p.endsWith(NOTEBOOK_FILE_SUFFIX));
|
|
@@ -24985,7 +25326,7 @@ function buildRuntimeForModel(job, malloyConfig) {
|
|
|
24985
25326
|
}
|
|
24986
25327
|
async function compileMalloyModel(job, malloyConfig, modelPath) {
|
|
24987
25328
|
const compileStart = performance.now();
|
|
24988
|
-
const fullPath =
|
|
25329
|
+
const fullPath = path3.join(job.packagePath, modelPath);
|
|
24989
25330
|
const modelURL = pathToFileURL(fullPath);
|
|
24990
25331
|
const importBaseURL = new URL(".", modelURL);
|
|
24991
25332
|
const { runtime, urlReader, textFor } = buildRuntimeForModel(job, malloyConfig);
|
|
@@ -25050,12 +25391,12 @@ async function compileMalloyModel(job, malloyConfig, modelPath) {
|
|
|
25050
25391
|
}
|
|
25051
25392
|
async function compileNotebookModel(job, malloyConfig, modelPath) {
|
|
25052
25393
|
const compileStart = performance.now();
|
|
25053
|
-
const fullPath =
|
|
25394
|
+
const fullPath = path3.join(job.packagePath, modelPath);
|
|
25054
25395
|
const modelURL = pathToFileURL(fullPath);
|
|
25055
25396
|
const importBaseURL = new URL(".", modelURL);
|
|
25056
25397
|
const { runtime, urlReader } = buildRuntimeForModel(job, malloyConfig);
|
|
25057
25398
|
const authorizeWarningCollection = authorizeWarningCollector();
|
|
25058
|
-
const fileContents = await
|
|
25399
|
+
const fileContents = await fs3.promises.readFile(modelURL, "utf8");
|
|
25059
25400
|
const parse = MalloySQLParser.parse(fileContents, modelPath);
|
|
25060
25401
|
let mm;
|
|
25061
25402
|
const perCellMM = parse.statements.map((stmt) => {
|