@malloy-publisher/server 0.9.0 → 0.9.2
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 +46 -5
- package/dist/app/api-doc.yaml +144 -54
- package/dist/app/assets/EnvironmentPage-B-t_QP32.js +1 -0
- package/dist/app/assets/{HomePage-D3MvQaZn.js → HomePage-Cpu2zMy-.js} +1 -1
- package/dist/app/assets/{LightMode-e1lNBfpL.js → LightMode-DOBl6awB.js} +1 -1
- package/dist/app/assets/MainPage-C7ySrclP.js +1 -0
- package/dist/app/assets/ModelPage-D8r_J-N9.js +2 -0
- package/dist/app/assets/PackagePage-CcVFBhnT.js +1 -0
- package/dist/app/assets/RenderedResult-CBLHr32C.es-DRr9Gmsz.js +141 -0
- package/dist/app/assets/{RouteError-BQnzPJvb.js → RouteError-mgOkv7XK.js} +1 -1
- package/dist/app/assets/ThemeEditorPage-CIPDs2w9.js +1 -0
- package/dist/app/assets/ToggleButtonGroup-CEZThrzh.js +1 -0
- package/dist/app/assets/{index-CCNqF0-G.js → index-Bg-M8sZz.js} +1 -1
- package/dist/app/assets/index-CGdwupPP.js +457 -0
- package/dist/app/assets/{index-CKmZ4HG7.js → index-CeLTZAFW.js} +116 -116
- package/dist/app/assets/{index-CdExa3Pk.js → index-DoF8ihra.js} +1 -1
- package/dist/app/assets/{index-ufFZR_K-.js → index-IC0jPCkR.js} +1 -1
- package/dist/app/assets/index.es-6eARPKZf.js +198 -0
- package/dist/app/index.html +1 -1
- package/dist/package_load_worker.mjs +571 -107
- package/dist/server.mjs +10356 -9719
- package/package.json +1 -1
- package/dist/app/assets/EnvironmentPage-UMS7Py4Q.js +0 -1
- package/dist/app/assets/MainPage-B0ozqtQO.js +0 -2
- package/dist/app/assets/ModelPage-lQj4Axqu.js +0 -2
- package/dist/app/assets/PackagePage-BT0YKNKU.js +0 -1
- package/dist/app/assets/RenderedResult-BRgIgxWh.es-DiE7kPNX.js +0 -136
- package/dist/app/assets/ThemeEditorPage-D6t7w9Js.js +0 -1
- package/dist/app/assets/ToggleButtonGroup-CJT2JKTC.js +0 -1
- package/dist/app/assets/index-TiWjmdoW.js +0 -450
- package/dist/app/assets/index.es-iUV0gCYk.js +0 -111
- package/dist/cpufeatures-1yrn0vtw.node +0 -0
|
@@ -13058,9 +13058,54 @@ function logInternalFailure(summary, error, level = "error") {
|
|
|
13058
13058
|
}
|
|
13059
13059
|
});
|
|
13060
13060
|
}
|
|
13061
|
-
function
|
|
13061
|
+
function filesystemAccessFailure(error) {
|
|
13062
|
+
let current = error;
|
|
13063
|
+
for (let depth = 0;depth < 8 && current instanceof Error; depth++) {
|
|
13064
|
+
const errno = current;
|
|
13065
|
+
if (typeof errno.code === "string" && errno.code in FILESYSTEM_ACCESS_DESCRIPTIONS && typeof errno.syscall === "string") {
|
|
13066
|
+
return errno;
|
|
13067
|
+
}
|
|
13068
|
+
current = errno.cause;
|
|
13069
|
+
}
|
|
13070
|
+
return;
|
|
13071
|
+
}
|
|
13072
|
+
function describeFilesystemAccessFailure(errno) {
|
|
13073
|
+
const code = errno.code ?? "";
|
|
13074
|
+
const target = errno.path ? ` '${errno.path}'` : "";
|
|
13075
|
+
return `${code}: ${FILESYSTEM_ACCESS_DESCRIPTIONS[code] ?? code}, ${errno.syscall}${target}`;
|
|
13076
|
+
}
|
|
13077
|
+
function messageWithFilesystemCause(error) {
|
|
13078
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13079
|
+
const access = filesystemAccessFailure(error);
|
|
13080
|
+
if (!access || message.includes(access.code ?? ""))
|
|
13081
|
+
return message;
|
|
13082
|
+
return `${message}: ${describeFilesystemAccessFailure(access)}`;
|
|
13083
|
+
}
|
|
13084
|
+
function errnoWireFields(error) {
|
|
13085
|
+
const { code, syscall, path } = error;
|
|
13086
|
+
if (typeof code !== "string")
|
|
13087
|
+
return;
|
|
13088
|
+
return {
|
|
13089
|
+
code,
|
|
13090
|
+
...typeof syscall === "string" ? { syscall } : {},
|
|
13091
|
+
...typeof path === "string" ? { path } : {}
|
|
13092
|
+
};
|
|
13093
|
+
}
|
|
13094
|
+
function internalErrorToHttpError(error, { log = true } = {}) {
|
|
13095
|
+
const logInternal = (...args) => {
|
|
13096
|
+
if (log)
|
|
13097
|
+
logInternalFailure(...args);
|
|
13098
|
+
};
|
|
13099
|
+
const access = filesystemAccessFailure(error);
|
|
13100
|
+
if (access) {
|
|
13101
|
+
logInternal("Filesystem access refused", error, "warn");
|
|
13102
|
+
return httpError(500, `The server cannot access a path it needs (${describeFilesystemAccessFailure(access)}). ` + `Give the user the server runs as access to it.`);
|
|
13103
|
+
}
|
|
13062
13104
|
if (error instanceof BadRequestError) {
|
|
13063
13105
|
return httpError(400, error.message);
|
|
13106
|
+
} else if (error instanceof ServerConfigurationError) {
|
|
13107
|
+
logInternal("Server configuration error", error, "warn");
|
|
13108
|
+
return httpError(500, error.message);
|
|
13064
13109
|
} else if (error instanceof FrozenConfigError) {
|
|
13065
13110
|
return httpError(403, error.message);
|
|
13066
13111
|
} else if (error instanceof AccessDeniedError) {
|
|
@@ -13106,7 +13151,7 @@ function internalErrorToHttpError(error) {
|
|
|
13106
13151
|
if (error.callerSafe) {
|
|
13107
13152
|
return httpError(502, error.message);
|
|
13108
13153
|
}
|
|
13109
|
-
|
|
13154
|
+
logInternal("Upstream connection error", error, "warn");
|
|
13110
13155
|
return httpError(502, GENERIC_UPSTREAM_MESSAGE);
|
|
13111
13156
|
} else if (error instanceof MaterializationNotFoundError) {
|
|
13112
13157
|
return httpError(404, error.message);
|
|
@@ -13117,7 +13162,7 @@ function internalErrorToHttpError(error) {
|
|
|
13117
13162
|
} else if (error instanceof WriteConflictError) {
|
|
13118
13163
|
return httpError(409, error.message);
|
|
13119
13164
|
} else if (error instanceof WriteRolledBackError) {
|
|
13120
|
-
|
|
13165
|
+
logInternal("Dashboard write rolled back", error, "warn");
|
|
13121
13166
|
return httpError(500, error.message);
|
|
13122
13167
|
} else if (error instanceof ServiceUnavailableError) {
|
|
13123
13168
|
return httpError(503, error.message);
|
|
@@ -13128,7 +13173,7 @@ function internalErrorToHttpError(error) {
|
|
|
13128
13173
|
} else if (error instanceof NotImplementedError) {
|
|
13129
13174
|
return httpError(501, error.message);
|
|
13130
13175
|
} else {
|
|
13131
|
-
|
|
13176
|
+
logInternal("Unhandled internal error", error);
|
|
13132
13177
|
return httpError(500, GENERIC_INTERNAL_MESSAGE);
|
|
13133
13178
|
}
|
|
13134
13179
|
}
|
|
@@ -13150,10 +13195,15 @@ function toQueryTextProblem(problem) {
|
|
|
13150
13195
|
...problem.at ? { at: { range: problem.at.range } } : {}
|
|
13151
13196
|
};
|
|
13152
13197
|
}
|
|
13153
|
-
var GENERIC_INTERNAL_MESSAGE = "Internal server error.", GENERIC_UPSTREAM_MESSAGE = "Upstream connection error.", MAX_LOGGED_DETAIL_CHARS = 2000, NotImplementedError, BadRequestError, InvalidArgumentError, CompileRefusedError, EnvironmentNotFoundError, PackageNotFoundError, ModelNotFoundError, DashboardNotFoundError, ConnectionNotFoundError, TableNotFoundError, ConnectionError, DestinationNotFoundError, ConnectionAuthError, UnsupportedCatalogFormatError, ModelCompilationError, PackageManifestError, MaterializationEligibilityError, PublisherConfigError, FrozenConfigError, AccessDeniedError, QueryCompileError, NotQueryableError, OffSurfaceError, MaterializationNotFoundError, MaterializationConflictError, WriteConflictError, WriteRolledBackError, 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, 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;
|
|
13154
13199
|
var init_errors = __esm(() => {
|
|
13155
13200
|
init_constants();
|
|
13156
13201
|
init_logger();
|
|
13202
|
+
FILESYSTEM_ACCESS_DESCRIPTIONS = {
|
|
13203
|
+
EACCES: "permission denied",
|
|
13204
|
+
EPERM: "operation not permitted",
|
|
13205
|
+
EROFS: "read-only file system"
|
|
13206
|
+
};
|
|
13157
13207
|
NotImplementedError = class NotImplementedError extends Error {
|
|
13158
13208
|
constructor(message) {
|
|
13159
13209
|
super(message);
|
|
@@ -13174,8 +13224,8 @@ var init_errors = __esm(() => {
|
|
|
13174
13224
|
}
|
|
13175
13225
|
};
|
|
13176
13226
|
PackageNotFoundError = class PackageNotFoundError extends Error {
|
|
13177
|
-
constructor(message) {
|
|
13178
|
-
super(message);
|
|
13227
|
+
constructor(message, options) {
|
|
13228
|
+
super(message, options);
|
|
13179
13229
|
}
|
|
13180
13230
|
};
|
|
13181
13231
|
ModelNotFoundError = class ModelNotFoundError extends Error {
|
|
@@ -13246,6 +13296,12 @@ var init_errors = __esm(() => {
|
|
|
13246
13296
|
this.cause = cause;
|
|
13247
13297
|
}
|
|
13248
13298
|
};
|
|
13299
|
+
ServerConfigurationError = class ServerConfigurationError extends Error {
|
|
13300
|
+
constructor(message) {
|
|
13301
|
+
super(message);
|
|
13302
|
+
this.name = "ServerConfigurationError";
|
|
13303
|
+
}
|
|
13304
|
+
};
|
|
13249
13305
|
FrozenConfigError = class FrozenConfigError extends Error {
|
|
13250
13306
|
constructor(message = `Publisher config can't be updated when ${PUBLISHER_CONFIG_NAME} has { "frozenConfig": true }`) {
|
|
13251
13307
|
super(message);
|
|
@@ -13292,19 +13348,25 @@ var init_errors = __esm(() => {
|
|
|
13292
13348
|
}
|
|
13293
13349
|
};
|
|
13294
13350
|
WriteRolledBackError = class WriteRolledBackError extends Error {
|
|
13295
|
-
constructor(message) {
|
|
13296
|
-
super(message);
|
|
13351
|
+
constructor(message, options) {
|
|
13352
|
+
super(message, options);
|
|
13297
13353
|
this.name = "WriteRolledBackError";
|
|
13298
13354
|
}
|
|
13299
13355
|
};
|
|
13356
|
+
WriteVerifyError = class WriteVerifyError extends Error {
|
|
13357
|
+
constructor(message, options) {
|
|
13358
|
+
super(message, options);
|
|
13359
|
+
this.name = "WriteVerifyError";
|
|
13360
|
+
}
|
|
13361
|
+
};
|
|
13300
13362
|
InvalidStateTransitionError = class InvalidStateTransitionError extends Error {
|
|
13301
13363
|
constructor(message) {
|
|
13302
13364
|
super(message);
|
|
13303
13365
|
}
|
|
13304
13366
|
};
|
|
13305
13367
|
ServiceUnavailableError = class ServiceUnavailableError extends Error {
|
|
13306
|
-
constructor(message) {
|
|
13307
|
-
super(message);
|
|
13368
|
+
constructor(message, options) {
|
|
13369
|
+
super(message, options);
|
|
13308
13370
|
}
|
|
13309
13371
|
};
|
|
13310
13372
|
PayloadTooLargeError = class PayloadTooLargeError extends Error {
|
|
@@ -13351,6 +13413,7 @@ var init_authorize_routes = __esm(() => {
|
|
|
13351
13413
|
|
|
13352
13414
|
// src/service/authorize.ts
|
|
13353
13415
|
import { payloadOf, routeOf } from "@malloydata/malloy";
|
|
13416
|
+
import { createRequire as createRequire2 } from "module";
|
|
13354
13417
|
function noteRoute(text) {
|
|
13355
13418
|
return routeOf({ value: text.trimStart() });
|
|
13356
13419
|
}
|
|
@@ -13399,7 +13462,7 @@ function motlyAuthorizePayloadPattern(route) {
|
|
|
13399
13462
|
return new RegExp(`^[ \\t]*[([{<][ \\t]*(?:${nearMissWordAlternation(route)})[ \\t]*[)\\]}>]`, "iu");
|
|
13400
13463
|
}
|
|
13401
13464
|
function malformedAuthorizeAttemptPattern(route) {
|
|
13402
|
-
return new RegExp(`^##?\\|?[ \\t]*[([{<]
|
|
13465
|
+
return new RegExp(`^##?\\|?[ \\t]*(?:[([{<][ \\t]*)?(?:${nearMissWordAlternation(route)})`, "iu");
|
|
13403
13466
|
}
|
|
13404
13467
|
function authorizeNoteContent(text) {
|
|
13405
13468
|
const route = canonicalAuthorizeRoute(noteRoute(text));
|
|
@@ -13410,12 +13473,144 @@ function authorizeNoteContent(text) {
|
|
|
13410
13473
|
function authorizeAnnotationRoute(text) {
|
|
13411
13474
|
return authorizeNoteContent(text)?.route;
|
|
13412
13475
|
}
|
|
13413
|
-
function
|
|
13414
|
-
|
|
13476
|
+
function loadMalloyParser() {
|
|
13477
|
+
try {
|
|
13478
|
+
const entry = createRequire2(import.meta.url).resolve("@malloydata/malloy");
|
|
13479
|
+
const loaded = createRequire2(entry)("./lang/run-malloy-parser");
|
|
13480
|
+
return typeof loaded.makeMalloyParser === "function" ? loaded.makeMalloyParser : null;
|
|
13481
|
+
} catch {
|
|
13482
|
+
return null;
|
|
13483
|
+
}
|
|
13415
13484
|
}
|
|
13416
|
-
function
|
|
13485
|
+
function malloyParserFactory() {
|
|
13486
|
+
if (makeMalloyParser === undefined)
|
|
13487
|
+
makeMalloyParser = parserLoader();
|
|
13488
|
+
return makeMalloyParser ?? undefined;
|
|
13489
|
+
}
|
|
13490
|
+
function lastCallerGuardRefusalKind() {
|
|
13491
|
+
return lastRefusalKind;
|
|
13492
|
+
}
|
|
13493
|
+
function proseRanges(text) {
|
|
13494
|
+
if (lastLexed.text !== text)
|
|
13495
|
+
lastLexed = { text, prose: lexProseRanges(text) };
|
|
13496
|
+
return lastLexed.prose;
|
|
13497
|
+
}
|
|
13498
|
+
function lexProseRanges(text) {
|
|
13499
|
+
const factory = malloyParserFactory();
|
|
13500
|
+
lexerMissing = !factory;
|
|
13501
|
+
if (!factory) {
|
|
13502
|
+
if (!warnedNoParser) {
|
|
13503
|
+
warnedNoParser = true;
|
|
13504
|
+
console.warn("Prose-aware caller-annotation guard disabled: @malloydata/malloy ./lang/run-malloy-parser could not be loaded; falling back to whole-text matching.");
|
|
13505
|
+
}
|
|
13506
|
+
return;
|
|
13507
|
+
}
|
|
13508
|
+
try {
|
|
13509
|
+
const counter = () => ({
|
|
13510
|
+
errors: 0,
|
|
13511
|
+
syntaxError() {
|
|
13512
|
+
this.errors++;
|
|
13513
|
+
}
|
|
13514
|
+
});
|
|
13515
|
+
const lexerErrors = counter();
|
|
13516
|
+
const parserErrors = counter();
|
|
13517
|
+
const { tokenStream, parser } = factory(text, {
|
|
13518
|
+
lexerErrorListener: lexerErrors,
|
|
13519
|
+
parserErrorListener: parserErrors
|
|
13520
|
+
});
|
|
13521
|
+
parser.malloyDocument();
|
|
13522
|
+
const vocabulary = tokenStream.tokenSource?.vocabulary;
|
|
13523
|
+
if (lexerErrors.errors > 0 || parserErrors.errors > 0 || typeof vocabulary?.getSymbolicName !== "function")
|
|
13524
|
+
return;
|
|
13525
|
+
const utf16 = [];
|
|
13526
|
+
for (let i = 0;i < text.length; ) {
|
|
13527
|
+
utf16.push(i);
|
|
13528
|
+
i += text.codePointAt(i) > 65535 ? 2 : 1;
|
|
13529
|
+
}
|
|
13530
|
+
utf16.push(text.length);
|
|
13531
|
+
const rangeOf = (token) => {
|
|
13532
|
+
const from = utf16[token.startIndex];
|
|
13533
|
+
const to = utf16[token.stopIndex + 1];
|
|
13534
|
+
return from === undefined || to === undefined || to < from ? undefined : [from, to];
|
|
13535
|
+
};
|
|
13536
|
+
const prose = [];
|
|
13537
|
+
let block;
|
|
13538
|
+
for (const token of tokenStream.getTokens()) {
|
|
13539
|
+
const name = vocabulary.getSymbolicName(token.type);
|
|
13540
|
+
const range = rangeOf(token);
|
|
13541
|
+
if (name === "BLOCK_ANNOTATION_TEXT" || name === "BLOCK_ANNOTATION_END") {
|
|
13542
|
+
if (!block || !range || token.startIndex !== block.next)
|
|
13543
|
+
return;
|
|
13544
|
+
if (name === "BLOCK_ANNOTATION_END") {
|
|
13545
|
+
block = undefined;
|
|
13546
|
+
} else {
|
|
13547
|
+
if (block.prose)
|
|
13548
|
+
prose.push(range);
|
|
13549
|
+
block.next = token.stopIndex + 1;
|
|
13550
|
+
}
|
|
13551
|
+
continue;
|
|
13552
|
+
}
|
|
13553
|
+
if (block)
|
|
13554
|
+
return;
|
|
13555
|
+
if (name === "BLOCK_ANNOTATION_BEGIN" || name === "DOC_BLOCK_ANNOTATION_BEGIN") {
|
|
13556
|
+
if (!range)
|
|
13557
|
+
return;
|
|
13558
|
+
block = {
|
|
13559
|
+
prose: PROSE_ROUTES.has(noteRoute(text.slice(...range)) ?? ""),
|
|
13560
|
+
next: token.stopIndex + 1
|
|
13561
|
+
};
|
|
13562
|
+
} else if (name === "ANNOTATION" || name === "DOC_ANNOTATION") {
|
|
13563
|
+
if (!range)
|
|
13564
|
+
return;
|
|
13565
|
+
if (PROSE_ROUTES.has(noteRoute(text.slice(...range)) ?? ""))
|
|
13566
|
+
prose.push([range[0] + 1, range[1]]);
|
|
13567
|
+
}
|
|
13568
|
+
}
|
|
13569
|
+
return block ? undefined : prose;
|
|
13570
|
+
} catch {
|
|
13571
|
+
return;
|
|
13572
|
+
}
|
|
13573
|
+
}
|
|
13574
|
+
function hasCallerAuthorizeAnnotation(callerText, precedingText = "") {
|
|
13575
|
+
if (!AUTHORIZE_ANNOTATION_ANYWHERE.test(callerText))
|
|
13576
|
+
return false;
|
|
13577
|
+
const text = precedingText + callerText;
|
|
13578
|
+
const bodies = proseRanges(text);
|
|
13579
|
+
lastRefusalKind = bodies !== undefined ? "lexed" : lexerMissing ? "no_lexer" : "whole_text";
|
|
13580
|
+
if (bodies === undefined)
|
|
13581
|
+
return true;
|
|
13582
|
+
const sticky = new RegExp(AUTHORIZE_TAG_LIKE, "iuy");
|
|
13583
|
+
const callerStart = precedingText.length;
|
|
13584
|
+
const from = text.lastIndexOf(`
|
|
13585
|
+
`, callerStart - 1) + 1;
|
|
13586
|
+
let body = 0;
|
|
13587
|
+
for (let at = text.indexOf("#", from);at !== -1; at = text.indexOf("#", at + 1)) {
|
|
13588
|
+
sticky.lastIndex = at;
|
|
13589
|
+
const hit = sticky.exec(text);
|
|
13590
|
+
if (!hit)
|
|
13591
|
+
continue;
|
|
13592
|
+
const end = at + hit[0].length;
|
|
13593
|
+
if (end <= callerStart)
|
|
13594
|
+
continue;
|
|
13595
|
+
while (body < bodies.length && bodies[body][1] <= at)
|
|
13596
|
+
body++;
|
|
13597
|
+
const [start, stop] = bodies[body] ?? [Infinity, -Infinity];
|
|
13598
|
+
if (!(start <= at && end <= stop))
|
|
13599
|
+
return true;
|
|
13600
|
+
}
|
|
13601
|
+
return false;
|
|
13602
|
+
}
|
|
13603
|
+
function assertNoCallerAuthorizeAnnotation(callerText, precedingText = "") {
|
|
13604
|
+
if (hasCallerAuthorizeAnnotation(callerText, precedingText))
|
|
13605
|
+
refuseCallerAuthorizeAnnotation();
|
|
13606
|
+
}
|
|
13607
|
+
function assertNoAuthorizeTagLike(callerText) {
|
|
13417
13608
|
if (!AUTHORIZE_ANNOTATION_ANYWHERE.test(callerText))
|
|
13418
13609
|
return;
|
|
13610
|
+
lastRefusalKind = "whole_text";
|
|
13611
|
+
refuseCallerAuthorizeAnnotation();
|
|
13612
|
+
}
|
|
13613
|
+
function refuseCallerAuthorizeAnnotation() {
|
|
13419
13614
|
throw new BadRequestError("An `authorize` annotation is not permitted in caller-submitted Malloy " + "text. Access gates are declared by the model author on the source; a " + "request cannot introduce, replace, or relax one. To validate a gate " + "you are authoring, save it to the package's model file and reload the " + "package — model load validates every `#(authorize)` annotation it " + "declares.");
|
|
13420
13615
|
}
|
|
13421
13616
|
function containsAuthorizeAnnotationTag(texts) {
|
|
@@ -13613,13 +13808,19 @@ ${rewrites}
|
|
|
13613
13808
|
` + `Test that the rewrite gates the same rows and check the row count ` + `matches what the string form served.`
|
|
13614
13809
|
});
|
|
13615
13810
|
}
|
|
13616
|
-
var AUTHORIZE_TAG_LIKE, AUTHORIZE_ANNOTATION_ANYWHERE, REGEXP_SPECIAL, GIVEN_REF_PATTERN, SINGLE_QUOTE_ESCAPE, DOUBLE_QUOTE_ESCAPE, STRING_LITERAL_PATTERN, everyMemberOf = () => (...members) => members, ROW_LEVEL_GATE_REJECTION_CAUSES, WHOLE_BODY_QUOTED_STRING, WHOLE_BODY_SINGLE_QUOTED_STRING;
|
|
13811
|
+
var AUTHORIZE_TAG_LIKE, AUTHORIZE_ANNOTATION_ANYWHERE, REGEXP_SPECIAL, PROSE_ROUTES, makeMalloyParser, parserLoader, warnedNoParser = false, lastLexed, lastRefusalKind = "lexed", lexerMissing = false, GIVEN_REF_PATTERN, SINGLE_QUOTE_ESCAPE, DOUBLE_QUOTE_ESCAPE, STRING_LITERAL_PATTERN, everyMemberOf = () => (...members) => members, ROW_LEVEL_GATE_REJECTION_CAUSES, WHOLE_BODY_QUOTED_STRING, WHOLE_BODY_SINGLE_QUOTED_STRING;
|
|
13617
13812
|
var init_authorize = __esm(() => {
|
|
13618
13813
|
init_errors();
|
|
13619
13814
|
init_authorize_routes();
|
|
13620
|
-
AUTHORIZE_TAG_LIKE = String.raw`##?\|?[ \t]*[([{<]
|
|
13815
|
+
AUTHORIZE_TAG_LIKE = String.raw`##?\|?[ \t]*(?:[([{<][ \t]*)?(?:(?:(?:row|source)[-_]?)?authorize|access[-_]?filter)(?=[)\]}>]|[ \t]|$)`;
|
|
13621
13816
|
AUTHORIZE_ANNOTATION_ANYWHERE = new RegExp(AUTHORIZE_TAG_LIKE, "iu");
|
|
13622
13817
|
REGEXP_SPECIAL = /[.*+?^${}()|[\]\\]/g;
|
|
13818
|
+
PROSE_ROUTES = new Set(["markdown", "text"]);
|
|
13819
|
+
parserLoader = loadMalloyParser;
|
|
13820
|
+
lastLexed = {
|
|
13821
|
+
text: "",
|
|
13822
|
+
prose: []
|
|
13823
|
+
};
|
|
13623
13824
|
GIVEN_REF_PATTERN = /\$([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
13624
13825
|
SINGLE_QUOTE_ESCAPE = /\\(['\\])/g;
|
|
13625
13826
|
DOUBLE_QUOTE_ESCAPE = /\\(["\\])/g;
|
|
@@ -13632,9 +13833,12 @@ var init_authorize = __esm(() => {
|
|
|
13632
13833
|
// src/authorize_metrics.ts
|
|
13633
13834
|
function recordAuthorizeGuardRejection(field) {
|
|
13634
13835
|
guardRejectionCounter ??= publisherMeter().createCounter("publisher_authorize_guard_rejected_total", {
|
|
13635
|
-
description: "Requests rejected with 400 for declaring an `#(authorize)` annotation in caller-submitted Malloy text.
|
|
13836
|
+
description: "Requests rejected with 400 for declaring an `#(authorize)` annotation in caller-submitted Malloy text. Labels: field ('query'|'source_name'|'query_name'|'compile_source'), match ('lexed' when Malloy's lexer placed a tag outside prose, 'whole_text' when the text could not be lexed cleanly or is a name, 'no_lexer' when Malloy's parser failed to load so every prose-bearing text refuses)."
|
|
13837
|
+
});
|
|
13838
|
+
guardRejectionCounter.add(1, {
|
|
13839
|
+
field,
|
|
13840
|
+
match: lastCallerGuardRefusalKind()
|
|
13636
13841
|
});
|
|
13637
|
-
guardRejectionCounter.add(1, { field });
|
|
13638
13842
|
}
|
|
13639
13843
|
function recordAuthorizeBypass(entryPoint) {
|
|
13640
13844
|
bypassCounter ??= publisherMeter().createCounter("publisher_authorize_bypass_total", {
|
|
@@ -13723,6 +13927,76 @@ var init_data_styles = __esm(() => {
|
|
|
13723
13927
|
init_logger();
|
|
13724
13928
|
});
|
|
13725
13929
|
|
|
13930
|
+
// src/package_load/error_wire.ts
|
|
13931
|
+
import { MalloyError as MalloyError2 } from "@malloydata/malloy";
|
|
13932
|
+
function serializeError(error) {
|
|
13933
|
+
const serialized = serializeErrorShape(error);
|
|
13934
|
+
const errno = error instanceof Error ? errnoWireFields(error) : undefined;
|
|
13935
|
+
return errno ? { ...serialized, errno } : serialized;
|
|
13936
|
+
}
|
|
13937
|
+
function serializeErrorShape(error) {
|
|
13938
|
+
if (error instanceof MalloyError2) {
|
|
13939
|
+
return {
|
|
13940
|
+
name: error.name,
|
|
13941
|
+
message: error.message,
|
|
13942
|
+
stack: error.stack,
|
|
13943
|
+
malloyProblems: error.problems,
|
|
13944
|
+
isCompilationError: true
|
|
13945
|
+
};
|
|
13946
|
+
}
|
|
13947
|
+
if (error instanceof ModelCompilationError) {
|
|
13948
|
+
return {
|
|
13949
|
+
name: error.name,
|
|
13950
|
+
message: error.message,
|
|
13951
|
+
stack: error.stack,
|
|
13952
|
+
isCompilationError: true
|
|
13953
|
+
};
|
|
13954
|
+
}
|
|
13955
|
+
if (error instanceof PackageManifestError) {
|
|
13956
|
+
return {
|
|
13957
|
+
name: error.name,
|
|
13958
|
+
message: error.message,
|
|
13959
|
+
stack: error.stack,
|
|
13960
|
+
isManifestError: true
|
|
13961
|
+
};
|
|
13962
|
+
}
|
|
13963
|
+
if (error instanceof Error) {
|
|
13964
|
+
return {
|
|
13965
|
+
name: error.name,
|
|
13966
|
+
message: error.message,
|
|
13967
|
+
stack: error.stack
|
|
13968
|
+
};
|
|
13969
|
+
}
|
|
13970
|
+
return { name: "Error", message: String(error) };
|
|
13971
|
+
}
|
|
13972
|
+
function deserializeError(serialized) {
|
|
13973
|
+
const err = new Error(serialized.message);
|
|
13974
|
+
err.name = serialized.name;
|
|
13975
|
+
if (serialized.stack)
|
|
13976
|
+
err.stack = serialized.stack;
|
|
13977
|
+
if (serialized.errno)
|
|
13978
|
+
Object.assign(err, serialized.errno);
|
|
13979
|
+
if (serialized.malloyProblems) {
|
|
13980
|
+
err.problems = serialized.malloyProblems;
|
|
13981
|
+
}
|
|
13982
|
+
if (serialized.isCompilationError) {
|
|
13983
|
+
const wrapped = new ModelCompilationError(err);
|
|
13984
|
+
if (serialized.stack)
|
|
13985
|
+
wrapped.stack = serialized.stack;
|
|
13986
|
+
return wrapped;
|
|
13987
|
+
}
|
|
13988
|
+
if (serialized.isManifestError) {
|
|
13989
|
+
const manifestError = new PackageManifestError(serialized.message);
|
|
13990
|
+
if (serialized.stack)
|
|
13991
|
+
manifestError.stack = serialized.stack;
|
|
13992
|
+
return manifestError;
|
|
13993
|
+
}
|
|
13994
|
+
return err;
|
|
13995
|
+
}
|
|
13996
|
+
var init_error_wire = __esm(() => {
|
|
13997
|
+
init_errors();
|
|
13998
|
+
});
|
|
13999
|
+
|
|
13726
14000
|
// src/service/annotations.ts
|
|
13727
14001
|
import { Annotations } from "@malloydata/malloy";
|
|
13728
14002
|
function isReservedRoute(route) {
|
|
@@ -14691,6 +14965,44 @@ var init_gate_classification = __esm(() => {
|
|
|
14691
14965
|
init_gate_registry_walk();
|
|
14692
14966
|
});
|
|
14693
14967
|
|
|
14968
|
+
// src/service/model_info.ts
|
|
14969
|
+
import { modelDefToModelInfo } from "@malloydata/malloy";
|
|
14970
|
+
function modelInfoOf(modelDef) {
|
|
14971
|
+
try {
|
|
14972
|
+
return modelDefToModelInfo(modelDef);
|
|
14973
|
+
} catch (err) {
|
|
14974
|
+
if (!isUnboundGiven(err) || !modelDef.givens)
|
|
14975
|
+
throw err;
|
|
14976
|
+
try {
|
|
14977
|
+
return modelDefToModelInfo({
|
|
14978
|
+
...modelDef,
|
|
14979
|
+
givens: withPlaceholderDefaults(modelDef.givens)
|
|
14980
|
+
});
|
|
14981
|
+
} catch {
|
|
14982
|
+
throw err;
|
|
14983
|
+
}
|
|
14984
|
+
}
|
|
14985
|
+
}
|
|
14986
|
+
function isUnboundGiven(err) {
|
|
14987
|
+
return err?.code === "compiler-given-no-value";
|
|
14988
|
+
}
|
|
14989
|
+
function withPlaceholderDefaults(givens) {
|
|
14990
|
+
const out = {};
|
|
14991
|
+
for (const [id, given] of Object.entries(givens)) {
|
|
14992
|
+
if (given.default !== undefined) {
|
|
14993
|
+
out[id] = given;
|
|
14994
|
+
continue;
|
|
14995
|
+
}
|
|
14996
|
+
const isFilter = given.type.type === "filter expression";
|
|
14997
|
+
out[id] = {
|
|
14998
|
+
...given,
|
|
14999
|
+
default: isFilter ? { node: "filterLiteral", filterSrc: "" } : { node: "null" }
|
|
15000
|
+
};
|
|
15001
|
+
}
|
|
15002
|
+
return out;
|
|
15003
|
+
}
|
|
15004
|
+
var init_model_info = () => {};
|
|
15005
|
+
|
|
14694
15006
|
// src/service/query_text.ts
|
|
14695
15007
|
import { ParseUtil } from "@malloydata/malloy-tag";
|
|
14696
15008
|
function extractRunTargetSourceName(query) {
|
|
@@ -15622,6 +15934,17 @@ function isNotebookModelPath(modelPath) {
|
|
|
15622
15934
|
const segments = modelPath.split("/");
|
|
15623
15935
|
return segments.length === 2 && segments[0] === NOTEBOOKS_DIR;
|
|
15624
15936
|
}
|
|
15937
|
+
function isDocumentModelPath(modelPath) {
|
|
15938
|
+
if (!modelPath.endsWith(MODEL_FILE_SUFFIX))
|
|
15939
|
+
return false;
|
|
15940
|
+
const segments = modelPath.split("/");
|
|
15941
|
+
return segments.length === 2 && (segments[0] === NOTEBOOKS_DIR || segments[0] === DASHBOARDS_DIR);
|
|
15942
|
+
}
|
|
15943
|
+
function documentKind(modelPath, tagKind) {
|
|
15944
|
+
if (tagKind === "notebook" || tagKind === "dashboard")
|
|
15945
|
+
return tagKind;
|
|
15946
|
+
return isNotebookModelPath(modelPath) ? "notebook" : "dashboard";
|
|
15947
|
+
}
|
|
15625
15948
|
function routeOfNote(text) {
|
|
15626
15949
|
return routeOf3({ value: text.trimStart() });
|
|
15627
15950
|
}
|
|
@@ -15649,34 +15972,71 @@ function dashboardDescriptionNotes(notes) {
|
|
|
15649
15972
|
return notes.filter((n) => line !== undefined && (n.at?.range.start.line ?? 0) > line).map((n) => n.text);
|
|
15650
15973
|
}
|
|
15651
15974
|
function hasArtifactLineOutsideBlocks(source, artifactLine) {
|
|
15975
|
+
return findArtifactLineOutsideBlocks(source, artifactLine) !== undefined;
|
|
15976
|
+
}
|
|
15977
|
+
function blockCloserFinder(lines) {
|
|
15978
|
+
const byKey = new Map;
|
|
15979
|
+
lines.forEach((line, at) => {
|
|
15980
|
+
const indent = /^[ \t]*/.exec(line)?.[0].length ?? 0;
|
|
15981
|
+
for (const closer of ["|##", "|#"])
|
|
15982
|
+
if (closesBlock(line, 0, indent, closer)) {
|
|
15983
|
+
const key = `${indent}${closer}`;
|
|
15984
|
+
const ats = byKey.get(key);
|
|
15985
|
+
if (ats)
|
|
15986
|
+
ats.push(at);
|
|
15987
|
+
else
|
|
15988
|
+
byKey.set(key, [at]);
|
|
15989
|
+
break;
|
|
15990
|
+
}
|
|
15991
|
+
});
|
|
15992
|
+
const cursor = new Map;
|
|
15993
|
+
return (column, closer, after) => {
|
|
15994
|
+
const key = `${column}${closer}`;
|
|
15995
|
+
const ats = byKey.get(key) ?? [];
|
|
15996
|
+
let k = cursor.get(key) ?? 0;
|
|
15997
|
+
while (k < ats.length && ats[k] <= after)
|
|
15998
|
+
k++;
|
|
15999
|
+
cursor.set(key, k);
|
|
16000
|
+
return ats[k] ?? -1;
|
|
16001
|
+
};
|
|
16002
|
+
}
|
|
16003
|
+
function findArtifactLineOutsideBlocks(source, artifactLine) {
|
|
15652
16004
|
const lines = source.split(/\r\n|\r|\n/);
|
|
16005
|
+
const closerAfter = blockCloserFinder(lines);
|
|
15653
16006
|
for (let i = 0;i < lines.length; i++) {
|
|
15654
16007
|
const trimmed = lines[i].trimStart();
|
|
15655
16008
|
const opener = /^(#{1,2})\|/.exec(trimmed);
|
|
15656
16009
|
if (opener) {
|
|
15657
|
-
const wanted = `|${opener[1]}`;
|
|
15658
|
-
if (trimmed.includes(wanted, opener[0].length))
|
|
15659
|
-
continue;
|
|
15660
16010
|
const column = lines[i].length - trimmed.length;
|
|
15661
|
-
|
|
15662
|
-
for (let at = i + 1;at < lines.length; at++)
|
|
15663
|
-
if (closesBlock(lines[at], 0, column, wanted)) {
|
|
15664
|
-
end = at;
|
|
15665
|
-
break;
|
|
15666
|
-
}
|
|
16011
|
+
const end = closerAfter(column, `|${opener[1]}`, i);
|
|
15667
16012
|
if (end !== -1) {
|
|
16013
|
+
const block = [trimmed, ...lines.slice(i + 1, end)].join(`
|
|
16014
|
+
`);
|
|
16015
|
+
if (artifactLine.test(block))
|
|
16016
|
+
return block;
|
|
15668
16017
|
i = end;
|
|
15669
16018
|
continue;
|
|
15670
16019
|
}
|
|
15671
16020
|
}
|
|
15672
16021
|
if (artifactLine.test(trimmed))
|
|
15673
|
-
return
|
|
16022
|
+
return trimmed;
|
|
15674
16023
|
}
|
|
15675
|
-
return
|
|
16024
|
+
return;
|
|
16025
|
+
}
|
|
16026
|
+
function artifactKindOfNotes(notes) {
|
|
16027
|
+
const tag = motlyTag(notes.map((note) => note.text).filter(isArtifactNoteText));
|
|
16028
|
+
return tagText(tag?.tag("artifact"), "kind");
|
|
15676
16029
|
}
|
|
15677
16030
|
function claimsToBeANotebook(source) {
|
|
15678
16031
|
return hasArtifactLineOutsideBlocks(source, ARTIFACT_NOTE);
|
|
15679
16032
|
}
|
|
16033
|
+
function artifactTagText(source) {
|
|
16034
|
+
return findArtifactLineOutsideBlocks(source, ARTIFACT_NOTE);
|
|
16035
|
+
}
|
|
16036
|
+
function artifactKindInText(source) {
|
|
16037
|
+
const line = artifactTagText(source);
|
|
16038
|
+
return line === undefined ? undefined : tagText(motlyTag([line])?.tag("artifact"), "kind");
|
|
16039
|
+
}
|
|
15680
16040
|
function parseNotebookText(text) {
|
|
15681
16041
|
try {
|
|
15682
16042
|
const { problems, parse } = translateToParse(text);
|
|
@@ -16113,9 +16473,12 @@ function readMarkdownBlocks(parse, text) {
|
|
|
16113
16473
|
return blocks;
|
|
16114
16474
|
}
|
|
16115
16475
|
function notebookReaderProblem(modelPath, text, modelDef, url) {
|
|
16116
|
-
if (!
|
|
16476
|
+
if (!isDocumentModelPath(modelPath))
|
|
16117
16477
|
return;
|
|
16118
|
-
|
|
16478
|
+
const notes = ownModelNoteObjects(modelDef);
|
|
16479
|
+
if (artifactNoteLine(notes) === undefined)
|
|
16480
|
+
return;
|
|
16481
|
+
if (documentKind(modelPath, artifactKindOfNotes(notes)) !== "notebook")
|
|
16119
16482
|
return;
|
|
16120
16483
|
const parse = parseNotebookText(text);
|
|
16121
16484
|
const error = isNotebookReaderError(parse) ? parse : readNotebookCells(parse, modelDef, text).error;
|
|
@@ -16135,7 +16498,7 @@ function notebookReaderProblem(modelPath, text, modelDef, url) {
|
|
|
16135
16498
|
}
|
|
16136
16499
|
};
|
|
16137
16500
|
}
|
|
16138
|
-
var NOTEBOOKS_DIR = "notebooks", 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) => {
|
|
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) => {
|
|
16139
16502
|
const accessor = node[name];
|
|
16140
16503
|
return typeof accessor === "function" ? accessor.call(node) : undefined;
|
|
16141
16504
|
}, STATEMENT_ACCESSORS, NOTEBOOK_PARSE_URL = "file:///publisher-notebook-reader/notebook.malloy", NOTE_TOKENS, TEXT_BLOCK_NAME;
|
|
@@ -16144,7 +16507,62 @@ var init_notebook = __esm(() => {
|
|
|
16144
16507
|
init_annotations();
|
|
16145
16508
|
init_query_text();
|
|
16146
16509
|
init_motly();
|
|
16147
|
-
ARTIFACT_NOTE =
|
|
16510
|
+
ARTIFACT_NOTE = {
|
|
16511
|
+
test(note) {
|
|
16512
|
+
const prefix = /^##\|?(?:[ \t\r\n]|$)/.exec(note);
|
|
16513
|
+
if (!prefix)
|
|
16514
|
+
return false;
|
|
16515
|
+
const bare = /[0-9A-Za-z_\u00C0-\u024F\u1E00-\u1EFF]+/y;
|
|
16516
|
+
let depth = 0;
|
|
16517
|
+
let before = "";
|
|
16518
|
+
for (let i = prefix[0].length;i < note.length; i++) {
|
|
16519
|
+
const c = note[i];
|
|
16520
|
+
if (/\s/.test(c))
|
|
16521
|
+
continue;
|
|
16522
|
+
if (note.startsWith("-...", i)) {
|
|
16523
|
+
i += 3;
|
|
16524
|
+
before = "";
|
|
16525
|
+
continue;
|
|
16526
|
+
}
|
|
16527
|
+
bare.lastIndex = i;
|
|
16528
|
+
const word = bare.exec(note)?.[0];
|
|
16529
|
+
if (c === '"' || c === "'") {
|
|
16530
|
+
const fence = note.startsWith(c.repeat(3), i) ? c.repeat(3) : c;
|
|
16531
|
+
i += fence.length;
|
|
16532
|
+
while (i < note.length && !note.startsWith(fence, i))
|
|
16533
|
+
i += note[i] === "\\" ? 2 : 1;
|
|
16534
|
+
i += fence.length - 1;
|
|
16535
|
+
} else if (c === "`") {
|
|
16536
|
+
let end = i + 1;
|
|
16537
|
+
while (end < note.length && note[end] !== "`" && note[end] !== `
|
|
16538
|
+
`)
|
|
16539
|
+
end += note[end] === "\\" ? 2 : 1;
|
|
16540
|
+
const name = note.slice(i + 1, end);
|
|
16541
|
+
if (depth === 0 && name === "artifact" && !/[=.-]/.test(before))
|
|
16542
|
+
return true;
|
|
16543
|
+
i = end;
|
|
16544
|
+
} else if (c === "#") {
|
|
16545
|
+
const eol = note.indexOf(`
|
|
16546
|
+
`, i);
|
|
16547
|
+
if (eol < 0)
|
|
16548
|
+
return false;
|
|
16549
|
+
i = eol;
|
|
16550
|
+
continue;
|
|
16551
|
+
} else if (c === "{" || c === "[")
|
|
16552
|
+
depth++;
|
|
16553
|
+
else if (c === "}" || c === "]")
|
|
16554
|
+
depth--;
|
|
16555
|
+
else if (word) {
|
|
16556
|
+
if (depth === 0 && word === "artifact" && !/[=.-]/.test(before))
|
|
16557
|
+
return true;
|
|
16558
|
+
i += word.length - 1;
|
|
16559
|
+
}
|
|
16560
|
+
before = c;
|
|
16561
|
+
}
|
|
16562
|
+
return false;
|
|
16563
|
+
}
|
|
16564
|
+
};
|
|
16565
|
+
ANY_ARTIFACT_NOTE = /^#{1,2}\|?(?=[ \t\r\n])(?:[^"'\\]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')*?(?<![\w\u00C0-\u024F\u1E00-\u1EFF.$-])artifact(?![\w\u00C0-\u024F\u1E00-\u1EFF])/;
|
|
16148
16566
|
STATEMENT_ACCESSORS = [
|
|
16149
16567
|
["runStatement", "run"],
|
|
16150
16568
|
["docAnnotations", "notes"],
|
|
@@ -22962,9 +23380,12 @@ var init_given = __esm(() => {
|
|
|
22962
23380
|
});
|
|
22963
23381
|
|
|
22964
23382
|
// src/service/dashboard.ts
|
|
22965
|
-
import { isSourceDef as isSourceDef5 } from "@malloydata/malloy";
|
|
23383
|
+
import { isJoined as isJoined3, isSourceDef as isSourceDef5 } from "@malloydata/malloy";
|
|
23384
|
+
function queryTiles(tiles) {
|
|
23385
|
+
return (tiles ?? []).filter((tile) => tile.kind === "query");
|
|
23386
|
+
}
|
|
22966
23387
|
function filterPublisherOwnedRenderLogs(logs, modelPath) {
|
|
22967
|
-
const couldBeATile =
|
|
23388
|
+
const couldBeATile = isDocumentModelPath(modelPath);
|
|
22968
23389
|
return logs.filter((log) => {
|
|
22969
23390
|
const match = UNKNOWN_RENDER_TAG.exec(log.message ?? "");
|
|
22970
23391
|
if (!match)
|
|
@@ -22989,6 +23410,24 @@ function dashboardSlug(modelPath) {
|
|
|
22989
23410
|
function matchesDocumentedDashboardName(slug) {
|
|
22990
23411
|
return /^[a-zA-Z0-9_-]+$/.test(slug);
|
|
22991
23412
|
}
|
|
23413
|
+
function readTileEntries(artifact) {
|
|
23414
|
+
return artifact.array("tiles")?.flatMap((entry) => {
|
|
23415
|
+
const text = tagText(entry);
|
|
23416
|
+
if (text === undefined)
|
|
23417
|
+
return [];
|
|
23418
|
+
if (tagText(entry, "kind") !== "text")
|
|
23419
|
+
return [{ kind: "query", expression: text }];
|
|
23420
|
+
const colspan = positiveInteger(tagNumeric(entry, "colspan"));
|
|
23421
|
+
return [
|
|
23422
|
+
{
|
|
23423
|
+
kind: "text",
|
|
23424
|
+
name: text,
|
|
23425
|
+
...colspan !== undefined && { colspan },
|
|
23426
|
+
...entry.has("break") && { break: true }
|
|
23427
|
+
}
|
|
23428
|
+
];
|
|
23429
|
+
});
|
|
23430
|
+
}
|
|
22992
23431
|
function readArtifactTag(tag, declaredType) {
|
|
22993
23432
|
const artifact = tag.tag("artifact");
|
|
22994
23433
|
if (!artifact)
|
|
@@ -22997,12 +23436,25 @@ function readArtifactTag(tag, declaredType) {
|
|
|
22997
23436
|
const autorun = readAutorun(artifact);
|
|
22998
23437
|
return {
|
|
22999
23438
|
title: tagText(artifact, "title"),
|
|
23000
|
-
|
|
23439
|
+
kind: tagText(artifact, "kind"),
|
|
23440
|
+
tiles: readTileEntries(artifact),
|
|
23001
23441
|
dashboardColumns: tag.tag("dashboard")?.has("columns") ? positiveInteger(tagNumeric(tag.tag("dashboard"), "columns")) : artifact.array("tiles") ? positiveInteger(tagNumeric(artifact, "dashboard_columns")) : undefined,
|
|
23002
23442
|
givens,
|
|
23003
23443
|
autorun
|
|
23004
23444
|
};
|
|
23005
23445
|
}
|
|
23446
|
+
function readTextBlocks(notes) {
|
|
23447
|
+
return notes.flatMap((note) => {
|
|
23448
|
+
const newline = note.indexOf(`
|
|
23449
|
+
`);
|
|
23450
|
+
const opener = parseMarkdownOpener(newline === -1 ? note : note.slice(0, newline));
|
|
23451
|
+
if (opener?.level !== 2 || !opener.name)
|
|
23452
|
+
return [];
|
|
23453
|
+
const body = newline === -1 ? "" : note.slice(newline + 1);
|
|
23454
|
+
return [{ name: opener.name, body: body.replace(/\r\n?/g, `
|
|
23455
|
+
`) }];
|
|
23456
|
+
});
|
|
23457
|
+
}
|
|
23006
23458
|
function positiveInteger(value) {
|
|
23007
23459
|
return value !== undefined && Number.isInteger(value) && value >= 1 ? value : undefined;
|
|
23008
23460
|
}
|
|
@@ -23050,6 +23502,11 @@ function readDashboardModelFacts(modelPath, modelDef, surfacedGivenNames, gatesB
|
|
|
23050
23502
|
for (const field of obj.fields) {
|
|
23051
23503
|
const fieldName = field.as || field.name;
|
|
23052
23504
|
fieldNames.add(fieldName);
|
|
23505
|
+
if (isJoined3(field)) {
|
|
23506
|
+
for (const joined of field.fields) {
|
|
23507
|
+
fieldNames.add(`${fieldName}.${joined.as || joined.name}`);
|
|
23508
|
+
}
|
|
23509
|
+
}
|
|
23053
23510
|
if (field.type === "turtle") {
|
|
23054
23511
|
const refs = new Set(sourceGivens);
|
|
23055
23512
|
collectGivenRefs(field.pipeline, refs);
|
|
@@ -23120,7 +23577,11 @@ function tagTextArray(tag, ...path) {
|
|
|
23120
23577
|
return items?.map((item) => tagText(item)).filter(isString);
|
|
23121
23578
|
}
|
|
23122
23579
|
function resolveTileGivens(tile, facts) {
|
|
23123
|
-
|
|
23580
|
+
const reads = referencedTileGivens(tile, facts);
|
|
23581
|
+
if (reads === undefined)
|
|
23582
|
+
return;
|
|
23583
|
+
const gateReads = facts.compiledTileGivens?.get(normalizeTileExpression(tile))?.gateReads ?? [];
|
|
23584
|
+
return Array.from(new Set([...reads, ...gateReads])).filter((name) => facts.givens.has(name));
|
|
23124
23585
|
}
|
|
23125
23586
|
function resolveTileLayout(tile, facts) {
|
|
23126
23587
|
const annotations = tileAnnotations(tile, facts);
|
|
@@ -23132,7 +23593,15 @@ function tileAnnotations(tile, facts) {
|
|
|
23132
23593
|
}
|
|
23133
23594
|
function referencedTileGivens(tile, facts) {
|
|
23134
23595
|
const normalized = normalizeTileExpression(tile);
|
|
23135
|
-
|
|
23596
|
+
const statically = facts.viewGivens.get(normalized) ?? facts.queries.find((query) => query.name === normalized)?.givens;
|
|
23597
|
+
const compiled = facts.compiledTileGivens?.get(normalized)?.reads;
|
|
23598
|
+
if (!compiled)
|
|
23599
|
+
return statically;
|
|
23600
|
+
const rank = (name) => {
|
|
23601
|
+
const at = statically?.indexOf(name) ?? -1;
|
|
23602
|
+
return at === -1 ? Number.MAX_SAFE_INTEGER : at;
|
|
23603
|
+
};
|
|
23604
|
+
return [...compiled].sort((a, b) => rank(a) - rank(b));
|
|
23136
23605
|
}
|
|
23137
23606
|
function buildGivenSpecs(names, facts) {
|
|
23138
23607
|
const declarations = facts.givens;
|
|
@@ -23174,26 +23643,41 @@ function buildDashboardManifest(facts) {
|
|
|
23174
23643
|
const modelTag = motlyTag(facts.modelAnnotations);
|
|
23175
23644
|
const declaredType = (name2) => facts.givens.get(name2)?.type;
|
|
23176
23645
|
const composite = modelTag ? readArtifactTag(modelTag, declaredType) : undefined;
|
|
23177
|
-
|
|
23178
|
-
|
|
23646
|
+
const kind = documentKind(facts.modelPath, composite?.kind);
|
|
23647
|
+
if (composite?.tiles && (composite.tiles.length > 0 || kind === "notebook")) {
|
|
23648
|
+
const blocks = readTextBlocks(facts.modelAnnotations);
|
|
23649
|
+
const tiles = composite.tiles.map((entry) => {
|
|
23650
|
+
if (entry.kind === "text") {
|
|
23651
|
+
return {
|
|
23652
|
+
kind: "text",
|
|
23653
|
+
name: entry.name,
|
|
23654
|
+
markdown: blocks.find((block) => block.name === entry.name)?.body ?? "",
|
|
23655
|
+
...entry.colspan !== undefined && { colspan: entry.colspan },
|
|
23656
|
+
...entry.break && { break: true }
|
|
23657
|
+
};
|
|
23658
|
+
}
|
|
23659
|
+
const query = entry.expression;
|
|
23179
23660
|
const givenNames = resolveTileGivens(query, facts);
|
|
23180
23661
|
const layout = resolveTileLayout(query, facts);
|
|
23181
23662
|
return {
|
|
23663
|
+
kind: "query",
|
|
23182
23664
|
query,
|
|
23183
23665
|
...givenNames ? { givenNames } : {},
|
|
23184
23666
|
...layout
|
|
23185
23667
|
};
|
|
23186
23668
|
});
|
|
23669
|
+
const queries = queryTiles(tiles);
|
|
23187
23670
|
const doc = docCommentTitleAndDescription(facts.descriptionNotes ?? facts.modelAnnotations, composite.title);
|
|
23188
23671
|
return {
|
|
23189
23672
|
...base,
|
|
23673
|
+
kind,
|
|
23190
23674
|
title: doc.title ?? name,
|
|
23191
23675
|
description: doc.description,
|
|
23192
23676
|
tiles,
|
|
23193
|
-
dashboardColumns: composite.dashboardColumns,
|
|
23677
|
+
dashboardColumns: kind === "notebook" ? 1 : composite.dashboardColumns,
|
|
23194
23678
|
startingGivens: composite.givens,
|
|
23195
23679
|
autorun: composite.autorun,
|
|
23196
|
-
givens: buildGivenSpecs(
|
|
23680
|
+
givens: buildGivenSpecs(queries.some((tile) => tile.givenNames === undefined) ? Array.from(facts.givens.keys()) : queries.flatMap((tile) => (referencedTileGivens(tile.query, facts) ?? []).filter((name2) => facts.givens.has(name2))), facts)
|
|
23197
23681
|
};
|
|
23198
23682
|
}
|
|
23199
23683
|
for (const query of facts.queries) {
|
|
@@ -23204,6 +23688,7 @@ function buildDashboardManifest(facts) {
|
|
|
23204
23688
|
const doc = docCommentTitleAndDescription(query.annotations, artifact.title);
|
|
23205
23689
|
return {
|
|
23206
23690
|
...base,
|
|
23691
|
+
kind: "dashboard",
|
|
23207
23692
|
title: doc.title ?? name,
|
|
23208
23693
|
description: doc.description,
|
|
23209
23694
|
query: query.name,
|
|
@@ -23245,19 +23730,33 @@ function lintDashboard(facts, manifest) {
|
|
|
23245
23730
|
continue;
|
|
23246
23731
|
add(`\`${property}\` in the artifact tag does nothing in Publisher` + (ARTIFACT_PROPERTY_REPLACEMENTS[property] ? `. ${ARTIFACT_PROPERTY_REPLACEMENTS[property]}` : property === "tiles" ? `: a dashboard whose tag sits on a query is that one query's ` + `result. Move the tag to model level (\`## artifact\`) to ` + `combine separate queries into a grid.` : `.`));
|
|
23247
23732
|
}
|
|
23733
|
+
const textBlocks = readTextBlocks(facts.modelAnnotations);
|
|
23248
23734
|
for (const entry of artifactTag?.array("tiles") ?? []) {
|
|
23249
23735
|
const kind = tagText(entry, "kind");
|
|
23250
|
-
|
|
23251
|
-
|
|
23736
|
+
const label = tagText(entry) ?? "a tile";
|
|
23737
|
+
const read = kind === "text" ? ["kind", "colspan", "break"] : [];
|
|
23738
|
+
const carried = Object.keys(entry.dict ?? {}).filter((property) => !read.includes(property) && !(property === "kind" && kind === "query"));
|
|
23739
|
+
if (carried.length > 0) {
|
|
23740
|
+
const named = carried.map((property) => `\`${property}\``).join(", ");
|
|
23741
|
+
add(kind === "text" ? `\`${label}\` in \`tiles=[…]\` carries ${named}, which Publisher does not read: a text tile's entry reads only \`colspan\` and \`break\`.` : `\`${label}\` in \`tiles=[…]\` carries ${named}, ` + `which Publisher does not read: a tile entry is the run expression ` + `alone. Per-tile presentation goes on the view the tile names ` + `(\`# colspan\`, \`# break\`, \`# label\`, \`# subtitle\`, ` + `\`# borderless\`).`);
|
|
23742
|
+
}
|
|
23743
|
+
if (kind !== "text")
|
|
23252
23744
|
continue;
|
|
23745
|
+
if (!textBlocks.some((block) => block.name === label)) {
|
|
23746
|
+
add(`text tile \`${label}\` has no \`##|(markdown) ${label}\` block, so it shows nothing. ` + `Fix: write that block, with the text on the lines below its opener and \`|##\` after.`);
|
|
23253
23747
|
}
|
|
23254
|
-
|
|
23255
|
-
|
|
23256
|
-
|
|
23257
|
-
|
|
23258
|
-
|
|
23748
|
+
if (entry.has("colspan") && positiveInteger(tagNumeric(entry, "colspan")) === undefined) {
|
|
23749
|
+
add(`colspan on text tile \`${label}\` must be a positive integer. The tile spans one column.`);
|
|
23750
|
+
}
|
|
23751
|
+
}
|
|
23752
|
+
const seenBlocks = new Set;
|
|
23753
|
+
for (const { name } of textBlocks) {
|
|
23754
|
+
if (seenBlocks.has(name)) {
|
|
23755
|
+
add(`the \`##|(markdown) ${name}\` block is written twice, and only the first is shown. Fix: rename or delete the second.`);
|
|
23756
|
+
}
|
|
23757
|
+
seenBlocks.add(name);
|
|
23259
23758
|
}
|
|
23260
|
-
for (const { query: tile } of manifest.
|
|
23759
|
+
for (const { query: tile } of manifest.kind === "notebook" ? [] : queryTiles(manifest.tiles)) {
|
|
23261
23760
|
const tag = motlyTag(tileAnnotations(tile, facts) ?? []);
|
|
23262
23761
|
if (!tag?.has("colspan"))
|
|
23263
23762
|
continue;
|
|
@@ -23276,21 +23775,28 @@ function lintDashboard(facts, manifest) {
|
|
|
23276
23775
|
}
|
|
23277
23776
|
const columnsTag = ownTag?.tag("dashboard");
|
|
23278
23777
|
if (columnsTag?.has("columns")) {
|
|
23279
|
-
|
|
23778
|
+
const width = positiveInteger(tagNumeric(columnsTag, "columns"));
|
|
23779
|
+
if (width === undefined) {
|
|
23280
23780
|
const raw = tagText(columnsTag, "columns");
|
|
23281
23781
|
add(`# dashboard { columns=… } must be a positive integer, got ` + `${raw === undefined ? "a value that could not be read" : JSON.stringify(raw)}. ` + `The grid falls back to the default.`);
|
|
23782
|
+
} else if (width > MAX_BUILDER_COLUMNS) {
|
|
23783
|
+
add(`# dashboard { columns=${width} } is wider than the builder offers (${MAX_BUILDER_COLUMNS}); the reader still renders it.`);
|
|
23282
23784
|
}
|
|
23283
23785
|
}
|
|
23284
|
-
for (const { query: tile } of manifest.tiles
|
|
23786
|
+
for (const { query: tile } of queryTiles(manifest.tiles)) {
|
|
23285
23787
|
const parts = plainTileParts(tile);
|
|
23286
23788
|
if (!parts)
|
|
23287
23789
|
continue;
|
|
23288
23790
|
const resolved = referencedTileGivens(tile, facts) !== undefined || "name" in parts && facts.queries.some((query) => query.name === parts.name);
|
|
23791
|
+
if (!resolved && "name" in parts && textBlocks.some((block) => block.name === parts.name)) {
|
|
23792
|
+
add(`tile "${tile}" names the ##|(markdown) ${tile} block but has no kind=text, so it is read as a query. Fix: write ${tile} { kind=text }`, "error");
|
|
23793
|
+
continue;
|
|
23794
|
+
}
|
|
23289
23795
|
if (!resolved) {
|
|
23290
23796
|
const detail = "source" in parts ? facts.sourceFields.has(parts.source) ? `source "${parts.source}" has no view "${parts.view}"` : `no source "${parts.source}" in this file` : `no query named "${parts.name}" in this file`;
|
|
23291
23797
|
add(`tile "${tile}" does not resolve: ${detail}.`, "error");
|
|
23292
23798
|
}
|
|
23293
|
-
const unbindable = (referencedTileGivens(tile, facts) ?? []).filter((name) => !facts.givens.has(name));
|
|
23799
|
+
const unbindable = Array.from(new Set(referencedTileGivens(tile, facts) ?? [])).filter((name) => !facts.givens.has(name));
|
|
23294
23800
|
for (const name of unbindable) {
|
|
23295
23801
|
add(`tile "${tile}" filters by given "${name}", which this file does ` + `not import, so no control is shown for it and it stays at its ` + `default. Add it to an import in ${facts.modelPath}.`);
|
|
23296
23802
|
}
|
|
@@ -23453,7 +23959,7 @@ function lintSelfDrills(facts) {
|
|
|
23453
23959
|
}
|
|
23454
23960
|
return Array.from(findings.values());
|
|
23455
23961
|
}
|
|
23456
|
-
var
|
|
23962
|
+
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", …].`;
|
|
23457
23963
|
var init_dashboard = __esm(() => {
|
|
23458
23964
|
init_annotations();
|
|
23459
23965
|
init_notebook();
|
|
@@ -23674,9 +24180,8 @@ var init_filter = __esm(() => {
|
|
|
23674
24180
|
|
|
23675
24181
|
// src/service/source_extraction.ts
|
|
23676
24182
|
import {
|
|
23677
|
-
isJoined as
|
|
23678
|
-
isSourceDef as isSourceDef6
|
|
23679
|
-
modelDefToModelInfo
|
|
24183
|
+
isJoined as isJoined4,
|
|
24184
|
+
isSourceDef as isSourceDef6
|
|
23680
24185
|
} from "@malloydata/malloy";
|
|
23681
24186
|
function joinFieldNamesUnresolvableDeclaration(field, modelDef) {
|
|
23682
24187
|
const ids = [field.referenceID, field.sourceID].filter((id) => !!id);
|
|
@@ -23707,7 +24212,7 @@ function considerNoteOwner(declaredBy, note, candidate) {
|
|
|
23707
24212
|
function collectSourceInfos(modelDef) {
|
|
23708
24213
|
const names = Object.keys(modelDef.contents).filter((name) => isSourceDef6(modelDef.contents[name]));
|
|
23709
24214
|
const exports = [...new Set([...modelDef.exports, ...names])];
|
|
23710
|
-
return
|
|
24215
|
+
return modelInfoOf({ ...modelDef, exports }).entries.filter((entry) => entry.kind === "source");
|
|
23711
24216
|
}
|
|
23712
24217
|
function extractSourcesFromModelDef(modelDef, givens, onParseError) {
|
|
23713
24218
|
const filterMap = new Map;
|
|
@@ -23845,7 +24350,7 @@ function extractSourcesFromModelDef(modelDef, givens, onParseError) {
|
|
|
23845
24350
|
continue;
|
|
23846
24351
|
}
|
|
23847
24352
|
const fieldName = field.as || field.name;
|
|
23848
|
-
if (
|
|
24353
|
+
if (isJoined4(field) && isSourceDef6(field)) {
|
|
23849
24354
|
const joinedStruct = field;
|
|
23850
24355
|
if (joinFieldNamesUnresolvableDeclaration(joinedStruct, modelDef)) {
|
|
23851
24356
|
continue;
|
|
@@ -23903,6 +24408,7 @@ var init_source_extraction = __esm(() => {
|
|
|
23903
24408
|
init_annotations();
|
|
23904
24409
|
init_authorize();
|
|
23905
24410
|
init_authorize_routes();
|
|
24411
|
+
init_model_info();
|
|
23906
24412
|
init_filter();
|
|
23907
24413
|
init_gate_registry_walk();
|
|
23908
24414
|
});
|
|
@@ -23935,16 +24441,16 @@ init_constants();
|
|
|
23935
24441
|
init_authorize_metrics();
|
|
23936
24442
|
init_data_styles();
|
|
23937
24443
|
init_errors();
|
|
24444
|
+
init_error_wire();
|
|
23938
24445
|
init_authorize();
|
|
23939
24446
|
init_gate_classification();
|
|
23940
24447
|
init_gate_dimension();
|
|
24448
|
+
init_model_info();
|
|
23941
24449
|
var import_recursive_readdir = __toESM(require_recursive_readdir(), 1);
|
|
23942
24450
|
import {
|
|
23943
24451
|
contextOverlay,
|
|
23944
24452
|
isSourceDef as isSourceDef7,
|
|
23945
24453
|
MalloyConfig,
|
|
23946
|
-
MalloyError as MalloyError2,
|
|
23947
|
-
modelDefToModelInfo as modelDefToModelInfo2,
|
|
23948
24454
|
Runtime
|
|
23949
24455
|
} from "@malloydata/malloy";
|
|
23950
24456
|
import {
|
|
@@ -24529,7 +25035,7 @@ async function compileMalloyModel(job, malloyConfig, modelPath) {
|
|
|
24529
25035
|
modelPath,
|
|
24530
25036
|
modelType: "model",
|
|
24531
25037
|
modelDef,
|
|
24532
|
-
modelInfo:
|
|
25038
|
+
modelInfo: modelInfoOf(modelDef),
|
|
24533
25039
|
sourceInfos,
|
|
24534
25040
|
sources,
|
|
24535
25041
|
queries,
|
|
@@ -24573,7 +25079,7 @@ async function compileNotebookModel(job, malloyConfig, modelPath) {
|
|
|
24573
25079
|
continue;
|
|
24574
25080
|
}
|
|
24575
25081
|
const currentModelDef = (await localMM.getModel())._modelDef;
|
|
24576
|
-
const currentInfo =
|
|
25082
|
+
const currentInfo = modelInfoOf(currentModelDef);
|
|
24577
25083
|
const newSources = collectSourceInfos(currentModelDef).filter((s) => !(s.name in oldSources));
|
|
24578
25084
|
for (const s of newSources)
|
|
24579
25085
|
oldSources[s.name] = s;
|
|
@@ -24655,7 +25161,7 @@ async function compileNotebookModel(job, malloyConfig, modelPath) {
|
|
|
24655
25161
|
modelPath,
|
|
24656
25162
|
modelType: "notebook",
|
|
24657
25163
|
modelDef: finalModelDef,
|
|
24658
|
-
modelInfo: finalModelDef ?
|
|
25164
|
+
modelInfo: finalModelDef ? modelInfoOf(finalModelDef) : undefined,
|
|
24659
25165
|
sourceInfos: finalSourceInfos,
|
|
24660
25166
|
sources: finalSources,
|
|
24661
25167
|
queries: finalQueries,
|
|
@@ -24722,48 +25228,6 @@ async function loadPackage(job) {
|
|
|
24722
25228
|
}
|
|
24723
25229
|
};
|
|
24724
25230
|
}
|
|
24725
|
-
function serializeError(error) {
|
|
24726
|
-
if (error instanceof MalloyError2) {
|
|
24727
|
-
return {
|
|
24728
|
-
name: error.name,
|
|
24729
|
-
message: error.message,
|
|
24730
|
-
stack: error.stack,
|
|
24731
|
-
malloyProblems: error.problems,
|
|
24732
|
-
isCompilationError: true
|
|
24733
|
-
};
|
|
24734
|
-
}
|
|
24735
|
-
if (error instanceof ModelCompilationError) {
|
|
24736
|
-
return {
|
|
24737
|
-
name: error.name,
|
|
24738
|
-
message: error.message,
|
|
24739
|
-
stack: error.stack,
|
|
24740
|
-
isCompilationError: true
|
|
24741
|
-
};
|
|
24742
|
-
}
|
|
24743
|
-
if (error instanceof PackageManifestError) {
|
|
24744
|
-
return {
|
|
24745
|
-
name: error.name,
|
|
24746
|
-
message: error.message,
|
|
24747
|
-
stack: error.stack,
|
|
24748
|
-
isManifestError: true
|
|
24749
|
-
};
|
|
24750
|
-
}
|
|
24751
|
-
if (error instanceof Error) {
|
|
24752
|
-
return {
|
|
24753
|
-
name: error.name,
|
|
24754
|
-
message: error.message,
|
|
24755
|
-
stack: error.stack
|
|
24756
|
-
};
|
|
24757
|
-
}
|
|
24758
|
-
return { name: "Error", message: String(error) };
|
|
24759
|
-
}
|
|
24760
|
-
function deserializeError(serialized) {
|
|
24761
|
-
const err = new Error(serialized.message);
|
|
24762
|
-
err.name = serialized.name;
|
|
24763
|
-
if (serialized.stack)
|
|
24764
|
-
err.stack = serialized.stack;
|
|
24765
|
-
return err;
|
|
24766
|
-
}
|
|
24767
25231
|
var shuttingDown = false;
|
|
24768
25232
|
var inFlightJobs = new Set;
|
|
24769
25233
|
port.on("message", (message) => {
|