@malloy-publisher/server 0.0.240 → 0.0.242
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/dist/app/api-doc.yaml +153 -46
- package/dist/app/assets/{EnvironmentPage-2oMC3DUO.js → EnvironmentPage-zu0NeDu-.js} +1 -1
- package/dist/app/assets/HomePage-kuBM3jiQ.js +1 -0
- package/dist/app/assets/{LightMode-BNaG4oAx.js → LightMode-DGBAdVPb.js} +1 -1
- package/dist/app/assets/{MainPage-Dje9yqIp.js → MainPage-CCVx9yPs.js} +2 -2
- package/dist/app/assets/{MaterializationsPage-D4jCpScu.js → MaterializationsPage-M-bWIx8L.js} +1 -1
- package/dist/app/assets/ModelPage-D-L2pqIy.js +1 -0
- package/dist/app/assets/{PackagePage-DlO2UBEI.js → PackagePage-BZglxDlj.js} +1 -1
- package/dist/app/assets/RouteError-DGoCQGam.js +1 -0
- package/dist/app/assets/{ThemeEditorPage-DZzT5zt4.js → ThemeEditorPage-e8MLf7SV.js} +1 -1
- package/dist/app/assets/{WorkbookPage-CfDz8XAp.js → WorkbookPage-C8ufpN5i.js} +1 -1
- package/dist/app/assets/{core-BGHaIj_q.es-BeNX3GvK.js → core-KFsKleo0.es-D6cYhbct.js} +1 -1
- package/dist/app/assets/{index-ByceOJbS.js → index-B-jw9EkA.js} +52 -52
- package/dist/app/assets/{index-BfV8vaZu.js → index-CDNkCta4.js} +1 -1
- package/dist/app/assets/{index-BeZphO3v.js → index-CLwzlAx6.js} +1 -1
- package/dist/app/assets/{index-DXjc2oZx.js → index-Dnef41hg.js} +1 -1
- package/dist/app/index.html +1 -1
- package/dist/runtime/publisher.js +1 -1
- package/dist/server.mjs +206 -37
- package/package.json +1 -1
- package/dist/app/assets/HomePage-DmgHdpH6.js +0 -1
- package/dist/app/assets/ModelPage-oI3O6TwY.js +0 -1
- package/dist/app/assets/RouteError-B5MgkwXx.js +0 -1
package/dist/server.mjs
CHANGED
|
@@ -269317,7 +269317,7 @@ class QueryController {
|
|
|
269317
269317
|
constructor(environmentStore) {
|
|
269318
269318
|
this.environmentStore = environmentStore;
|
|
269319
269319
|
}
|
|
269320
|
-
async getQuery(environmentName, packageName, modelPath, sourceName, queryName, query, compactJson = false, filterParams, bypassFilters, givens, metadata) {
|
|
269320
|
+
async getQuery(environmentName, packageName, modelPath, sourceName, queryName, query, compactJson = false, filterParams, bypassFilters, givens, metadata, bypassAuthorize) {
|
|
269321
269321
|
let requestMetadata;
|
|
269322
269322
|
let queryClass;
|
|
269323
269323
|
try {
|
|
@@ -269357,7 +269357,7 @@ class QueryController {
|
|
|
269357
269357
|
return null;
|
|
269358
269358
|
}
|
|
269359
269359
|
}
|
|
269360
|
-
}, compactJson ? "compact" : "full"), getQueryTimeoutMs());
|
|
269360
|
+
}, compactJson ? "compact" : "full", bypassAuthorize), getQueryTimeoutMs());
|
|
269361
269361
|
const renderLogs = import_render_validator.validateRenderTags(result);
|
|
269362
269362
|
return {
|
|
269363
269363
|
result: serializedResult,
|
|
@@ -277169,12 +277169,19 @@ function unwrapQuotedExpression(body) {
|
|
|
277169
277169
|
|
|
277170
277170
|
// src/authorize_metrics.ts
|
|
277171
277171
|
var guardRejectionCounter = null;
|
|
277172
|
+
var bypassCounter = null;
|
|
277172
277173
|
function recordAuthorizeGuardRejection(field) {
|
|
277173
277174
|
guardRejectionCounter ??= publisherMeter().createCounter("publisher_authorize_guard_rejected_total", {
|
|
277174
277175
|
description: "Requests rejected with 400 for declaring an `#(authorize)` annotation in caller-submitted Malloy text. Label: field ('query'|'source_name'|'query_name'|'compile_source')."
|
|
277175
277176
|
});
|
|
277176
277177
|
guardRejectionCounter.add(1, { field });
|
|
277177
277178
|
}
|
|
277179
|
+
function recordAuthorizeBypass(entryPoint) {
|
|
277180
|
+
bypassCounter ??= publisherMeter().createCounter("publisher_authorize_bypass_total", {
|
|
277181
|
+
description: "Gate evaluations skipped because the request carried an authorize bypass (private data-management path). Label: entry_point ('source'|'runnable'). Any nonzero value on a path that should not use the bypass is a finding — see the paired `authorize bypass` audit log line for org/package/model/source."
|
|
277182
|
+
});
|
|
277183
|
+
bypassCounter.add(1, { entry_point: entryPoint });
|
|
277184
|
+
}
|
|
277178
277185
|
|
|
277179
277186
|
// src/service/environment.ts
|
|
277180
277187
|
init_logger();
|
|
@@ -278733,7 +278740,11 @@ class Model {
|
|
|
278733
278740
|
}
|
|
278734
278741
|
return this.fileLevelAuthorize;
|
|
278735
278742
|
}
|
|
278736
|
-
async assertAuthorized(sourceName, givens) {
|
|
278743
|
+
async assertAuthorized(sourceName, givens, bypassAuthorize = false) {
|
|
278744
|
+
if (bypassAuthorize) {
|
|
278745
|
+
this.noteAuthorizeBypass("source", sourceName);
|
|
278746
|
+
return;
|
|
278747
|
+
}
|
|
278737
278748
|
const gates = sourceName ? this.entryPointGatesBySource.get(sourceName) : undefined;
|
|
278738
278749
|
if (gates) {
|
|
278739
278750
|
for (const { label, exprs, selfContained, ambientPrefix } of gates) {
|
|
@@ -278743,6 +278754,15 @@ class Model {
|
|
|
278743
278754
|
}
|
|
278744
278755
|
await this.assertAuthorizedExprs(sourceName ?? "(query)", this.effectiveAuthorizeFor(sourceName), givens);
|
|
278745
278756
|
}
|
|
278757
|
+
noteAuthorizeBypass(entryPoint, sourceName) {
|
|
278758
|
+
recordAuthorizeBypass(entryPoint);
|
|
278759
|
+
logger.info("authorize bypass", {
|
|
278760
|
+
entryPoint,
|
|
278761
|
+
sourceName: sourceName ?? "(query)",
|
|
278762
|
+
modelPath: this.modelPath,
|
|
278763
|
+
packageName: this.packageName
|
|
278764
|
+
});
|
|
278765
|
+
}
|
|
278746
278766
|
async assertAuthorizedExprs(label, exprs, givens, selfContainedFirst = false, ambientPrefix = 0) {
|
|
278747
278767
|
if (exprs.length === 0)
|
|
278748
278768
|
return;
|
|
@@ -278765,7 +278785,11 @@ class Model {
|
|
|
278765
278785
|
if (!passed)
|
|
278766
278786
|
deny();
|
|
278767
278787
|
}
|
|
278768
|
-
async assertAuthorizedForAllSources(runnable, givens) {
|
|
278788
|
+
async assertAuthorizedForAllSources(runnable, givens, bypassAuthorize = false) {
|
|
278789
|
+
if (bypassAuthorize) {
|
|
278790
|
+
this.noteAuthorizeBypass("runnable", await this.resolveAuthorizeSourceFromRunnable(runnable));
|
|
278791
|
+
return;
|
|
278792
|
+
}
|
|
278769
278793
|
const ownSourceName = await this.resolveAuthorizeSourceFromRunnable(runnable);
|
|
278770
278794
|
await this.assertAuthorized(ownSourceName, givens);
|
|
278771
278795
|
const { struct, modelDef, compositeResolvedSourceDef } = await this.resolveRunTargetStruct(runnable);
|
|
@@ -279342,7 +279366,7 @@ class Model {
|
|
|
279342
279366
|
return { ...b, schema, refinements };
|
|
279343
279367
|
}).filter((b) => b.schema.length > 0);
|
|
279344
279368
|
}
|
|
279345
|
-
async getQueryResults(sourceName, queryName, query, filterParams, bypassFilters, givens, abortSignal, queryMetadataInput, responseShape = "full") {
|
|
279369
|
+
async getQueryResults(sourceName, queryName, query, filterParams, bypassFilters, givens, abortSignal, queryMetadataInput, responseShape = "full", bypassAuthorize = false) {
|
|
279346
279370
|
const startTime = performance.now();
|
|
279347
279371
|
if (this.compilationError) {
|
|
279348
279372
|
if (this.compilationError instanceof MalloyError2 || this.compilationError instanceof ModelCompilationError) {
|
|
@@ -279361,7 +279385,7 @@ class Model {
|
|
|
279361
279385
|
const surfaceName = extractRunTargetSourceName(query);
|
|
279362
279386
|
const earlySource = sourceName || (queryName ? this.queries?.find((q) => q.name === queryName)?.sourceName : undefined) || (surfaceName && !this.sources?.some((s) => s.name === surfaceName) ? this.queries?.find((q) => q.name === surfaceName)?.sourceName : undefined) || surfaceName;
|
|
279363
279387
|
if (earlySource) {
|
|
279364
|
-
await this.assertAuthorized(earlySource, givens ?? {});
|
|
279388
|
+
await this.assertAuthorized(earlySource, givens ?? {}, bypassAuthorize);
|
|
279365
279389
|
}
|
|
279366
279390
|
try {
|
|
279367
279391
|
for (const [field, callerText] of [
|
|
@@ -279456,7 +279480,7 @@ run: ${sourceName ? `${quoteMalloyIdentifier(sourceName)} -> ` : ""}${quoteMallo
|
|
|
279456
279480
|
if (boundary === "deferred") {
|
|
279457
279481
|
this.assertQueryBoundaryCompiled(compiledSource, query);
|
|
279458
279482
|
}
|
|
279459
|
-
await this.assertAuthorizedForAllSources(runnable, givens ?? {});
|
|
279483
|
+
await this.assertAuthorizedForAllSources(runnable, givens ?? {}, bypassAuthorize);
|
|
279460
279484
|
const maxRows = getMaxQueryRows();
|
|
279461
279485
|
const maxBytes = getMaxResponseBytes();
|
|
279462
279486
|
const buildManifest = this.resolveFreshBuildManifest();
|
|
@@ -280652,7 +280676,7 @@ function ledgerLineageMismatch(entry, lineage) {
|
|
|
280652
280676
|
}
|
|
280653
280677
|
const changed = (reason) => ({ reasonCode: "lineage_changed", reason });
|
|
280654
280678
|
if (entry.sourceEntityId !== lineage.sourceEntityId) {
|
|
280655
|
-
return changed(`the source's content address
|
|
280679
|
+
return changed(`the source's content address is not the one the recorded boundary was ` + `measured under, so that boundary describes different SQL than this ` + `refresh would apply a delta to — either the model was edited, or ` + `this refresh is instructed through a different version of the ` + `package than the one that advanced the boundary`);
|
|
280656
280680
|
}
|
|
280657
280681
|
if (entry.connectionName !== lineage.connectionName) {
|
|
280658
280682
|
return changed(`the recorded boundary was advanced on connection ` + `"${entry.connectionName}", not "${lineage.connectionName}"`);
|
|
@@ -284408,6 +284432,13 @@ class WatchModeController {
|
|
|
284408
284432
|
init_errors();
|
|
284409
284433
|
init_logger();
|
|
284410
284434
|
|
|
284435
|
+
// src/authorize_bypass_header.ts
|
|
284436
|
+
var BYPASS_AUTHORIZE_HEADER = "x-publisher-bypass-authorize";
|
|
284437
|
+
var readBypassAuthorize = (req) => {
|
|
284438
|
+
const raw = req.headers[BYPASS_AUTHORIZE_HEADER];
|
|
284439
|
+
return typeof raw === "string" && raw.trim().toLowerCase() === "true" ? true : undefined;
|
|
284440
|
+
};
|
|
284441
|
+
|
|
284411
284442
|
// src/filter_deprecation.ts
|
|
284412
284443
|
var setFilterDeprecationHeaders = (res, options) => {
|
|
284413
284444
|
const hasFilterParams = options.filterParams !== undefined && options.filterParams !== null && !(typeof options.filterParams === "object" && !Array.isArray(options.filterParams) && Object.keys(options.filterParams).length === 0);
|
|
@@ -284559,6 +284590,9 @@ class MaterializationController {
|
|
|
284559
284590
|
if (parsed.strictUpstreams !== undefined) {
|
|
284560
284591
|
result.strictUpstreams = parsed.strictUpstreams;
|
|
284561
284592
|
}
|
|
284593
|
+
if (parsed.ledger !== undefined) {
|
|
284594
|
+
result.ledger = parsed.ledger;
|
|
284595
|
+
}
|
|
284562
284596
|
}
|
|
284563
284597
|
if (body.forceRefresh !== undefined) {
|
|
284564
284598
|
if (typeof body.forceRefresh !== "boolean") {
|
|
@@ -284628,6 +284662,12 @@ class MaterializationController {
|
|
|
284628
284662
|
}
|
|
284629
284663
|
result.strictUpstreams = obj.strictUpstreams;
|
|
284630
284664
|
}
|
|
284665
|
+
if (obj.ledger !== undefined && obj.ledger !== null) {
|
|
284666
|
+
if (!Array.isArray(obj.ledger)) {
|
|
284667
|
+
throw new BadRequestError("buildInstructions.ledger must be an array");
|
|
284668
|
+
}
|
|
284669
|
+
result.ledger = obj.ledger.map((entry) => this.validateLedgerEntry(entry));
|
|
284670
|
+
}
|
|
284631
284671
|
return result;
|
|
284632
284672
|
}
|
|
284633
284673
|
validateManifestReference(raw) {
|
|
@@ -284678,6 +284718,40 @@ class MaterializationController {
|
|
|
284678
284718
|
...typeof instruction.reseed === "boolean" ? { reseed: instruction.reseed } : {}
|
|
284679
284719
|
};
|
|
284680
284720
|
}
|
|
284721
|
+
validateLedgerEntry(raw) {
|
|
284722
|
+
if (typeof raw !== "object" || raw === null) {
|
|
284723
|
+
throw new BadRequestError("Each buildInstructions.ledger entry must be an object");
|
|
284724
|
+
}
|
|
284725
|
+
const entry = raw;
|
|
284726
|
+
for (const field of [
|
|
284727
|
+
"connectionName",
|
|
284728
|
+
"physicalTableName",
|
|
284729
|
+
"coveredThrough",
|
|
284730
|
+
"coveredThroughType",
|
|
284731
|
+
"watermark",
|
|
284732
|
+
"sourceEntityId"
|
|
284733
|
+
]) {
|
|
284734
|
+
if (typeof entry[field] !== "string" || entry[field] === "") {
|
|
284735
|
+
throw new BadRequestError(`Ledger entry '${field}' must be a non-empty string`);
|
|
284736
|
+
}
|
|
284737
|
+
}
|
|
284738
|
+
if (entry.strategy !== "merge" && entry.strategy !== "range_replace") {
|
|
284739
|
+
throw new BadRequestError("Ledger entry 'strategy' must be 'merge' or 'range_replace'");
|
|
284740
|
+
}
|
|
284741
|
+
if (entry.mergeKeys !== undefined && (!Array.isArray(entry.mergeKeys) || entry.mergeKeys.some((k) => typeof k !== "string"))) {
|
|
284742
|
+
throw new BadRequestError("Ledger entry 'mergeKeys' must be an array of strings");
|
|
284743
|
+
}
|
|
284744
|
+
return {
|
|
284745
|
+
connectionName: entry.connectionName,
|
|
284746
|
+
physicalTableName: entry.physicalTableName,
|
|
284747
|
+
coveredThrough: entry.coveredThrough,
|
|
284748
|
+
coveredThroughType: entry.coveredThroughType,
|
|
284749
|
+
watermark: entry.watermark,
|
|
284750
|
+
strategy: entry.strategy,
|
|
284751
|
+
sourceEntityId: entry.sourceEntityId,
|
|
284752
|
+
...Array.isArray(entry.mergeKeys) ? { mergeKeys: entry.mergeKeys } : {}
|
|
284753
|
+
};
|
|
284754
|
+
}
|
|
284681
284755
|
async stopMaterialization(environmentName, packageName, materializationId) {
|
|
284682
284756
|
return this.materializationService.stopMaterialization(environmentName, packageName, materializationId);
|
|
284683
284757
|
}
|
|
@@ -292742,6 +292816,25 @@ import { Manifest } from "@malloydata/malloy";
|
|
|
292742
292816
|
|
|
292743
292817
|
// src/service/incremental_build.ts
|
|
292744
292818
|
init_logger();
|
|
292819
|
+
function ledgerTableKey(connectionName, physicalTableName) {
|
|
292820
|
+
return `${connectionName}\x00${physicalTableName}`;
|
|
292821
|
+
}
|
|
292822
|
+
function indexCallerLedger(entries) {
|
|
292823
|
+
const index = new Map;
|
|
292824
|
+
for (const entry of entries) {
|
|
292825
|
+
index.set(ledgerTableKey(entry.connectionName, entry.physicalTableName), {
|
|
292826
|
+
sourceEntityId: entry.sourceEntityId,
|
|
292827
|
+
coveredThroughValue: entry.coveredThrough,
|
|
292828
|
+
coveredThroughType: entry.coveredThroughType,
|
|
292829
|
+
watermarkDimension: entry.watermark,
|
|
292830
|
+
mergeKeyDimensions: entry.mergeKeys ?? [],
|
|
292831
|
+
derivedStrategy: entry.strategy,
|
|
292832
|
+
physicalTableName: entry.physicalTableName,
|
|
292833
|
+
connectionName: entry.connectionName
|
|
292834
|
+
});
|
|
292835
|
+
}
|
|
292836
|
+
return index;
|
|
292837
|
+
}
|
|
292745
292838
|
function incrementalLineage(params) {
|
|
292746
292839
|
const d = params.declaration;
|
|
292747
292840
|
if (!d?.incremental)
|
|
@@ -292769,25 +292862,32 @@ function incrementalLineage(params) {
|
|
|
292769
292862
|
}
|
|
292770
292863
|
async function planSourceRefresh(params) {
|
|
292771
292864
|
const { context, lineage } = params;
|
|
292865
|
+
const forceRefresh = context.forceRefresh || params.reseed === true;
|
|
292866
|
+
const dialect = params.persistSource.dialectName;
|
|
292772
292867
|
let ledgerEntry = null;
|
|
292773
|
-
|
|
292774
|
-
ledgerEntry =
|
|
292775
|
-
}
|
|
292776
|
-
|
|
292777
|
-
|
|
292778
|
-
|
|
292779
|
-
|
|
292780
|
-
|
|
292868
|
+
if (context.callerLedger) {
|
|
292869
|
+
ledgerEntry = context.callerLedger.get(ledgerTableKey(lineage.connectionName, lineage.physicalTableName)) ?? null;
|
|
292870
|
+
} else {
|
|
292871
|
+
try {
|
|
292872
|
+
ledgerEntry = await context.ledger.getIncrementalLedgerEntry(context.environmentId, lineage.connectionName, lineage.physicalTableName);
|
|
292873
|
+
} catch (err) {
|
|
292874
|
+
return {
|
|
292875
|
+
mode: "seed",
|
|
292876
|
+
reasonCode: "ledger_unreadable",
|
|
292877
|
+
reason: `the covered_through ledger could not be read (${errMessage(err)})`
|
|
292878
|
+
};
|
|
292879
|
+
}
|
|
292781
292880
|
}
|
|
292782
|
-
const postgresVersionNum = lineage.strategy === "merge" &&
|
|
292881
|
+
const postgresVersionNum = lineage.strategy === "merge" && dialect === "postgres" && ledgerEntry !== null ? await probePostgresVersion(params.runner) : undefined;
|
|
292882
|
+
let step;
|
|
292783
292883
|
try {
|
|
292784
|
-
|
|
292884
|
+
step = await planIncrementalStep({
|
|
292785
292885
|
runner: params.runner,
|
|
292786
|
-
dialect
|
|
292886
|
+
dialect,
|
|
292787
292887
|
quotedTablePath: params.quotedTablePath,
|
|
292788
292888
|
lineage,
|
|
292789
292889
|
ledgerEntry,
|
|
292790
|
-
forceRefresh
|
|
292890
|
+
forceRefresh,
|
|
292791
292891
|
now: context.now,
|
|
292792
292892
|
sourceSQL: params.sourceSQL,
|
|
292793
292893
|
columns: params.columns,
|
|
@@ -292800,9 +292900,15 @@ async function planSourceRefresh(params) {
|
|
|
292800
292900
|
reason: `the delta could not be planned (${errMessage(err)})`
|
|
292801
292901
|
};
|
|
292802
292902
|
}
|
|
292903
|
+
if (context.callerLedger && step.mode === "seed" && (step.reasonCode === "lineage_changed" || step.reasonCode === "table_renamed")) {
|
|
292904
|
+
throw new Error(`The supplied ledger entry for table "${lineage.physicalTableName}" ` + `was measured under a different definition of this source: ` + `${step.reason}. Delete the entry to rebuild the source, or set ` + `reseed.`);
|
|
292905
|
+
}
|
|
292906
|
+
return step;
|
|
292803
292907
|
}
|
|
292804
292908
|
async function advanceLedger(params) {
|
|
292805
292909
|
const { context, lineage } = params;
|
|
292910
|
+
if (context.callerLedger)
|
|
292911
|
+
return;
|
|
292806
292912
|
try {
|
|
292807
292913
|
await context.ledger.upsertIncrementalLedgerEntry({
|
|
292808
292914
|
environmentId: context.environmentId,
|
|
@@ -292827,6 +292933,8 @@ async function advanceLedger(params) {
|
|
|
292827
292933
|
}
|
|
292828
292934
|
}
|
|
292829
292935
|
async function resetLedger(context, lineage) {
|
|
292936
|
+
if (context.callerLedger)
|
|
292937
|
+
return;
|
|
292830
292938
|
try {
|
|
292831
292939
|
await context.ledger.deleteIncrementalLedgerEntry(context.environmentId, lineage.connectionName, lineage.physicalTableName);
|
|
292832
292940
|
} catch (err) {
|
|
@@ -293135,8 +293243,24 @@ async function resolveEnvironmentId(repository, environmentName) {
|
|
|
293135
293243
|
}
|
|
293136
293244
|
|
|
293137
293245
|
// src/service/materialization_service.ts
|
|
293138
|
-
function
|
|
293139
|
-
return
|
|
293246
|
+
function refreshFields(did) {
|
|
293247
|
+
return did ? { refresh: did } : {};
|
|
293248
|
+
}
|
|
293249
|
+
function ledgerFields(lineage, bound) {
|
|
293250
|
+
if (!lineage || !bound)
|
|
293251
|
+
return {};
|
|
293252
|
+
return {
|
|
293253
|
+
ledger: {
|
|
293254
|
+
connectionName: lineage.connectionName,
|
|
293255
|
+
physicalTableName: lineage.physicalTableName,
|
|
293256
|
+
coveredThrough: bound.value,
|
|
293257
|
+
coveredThroughType: bound.malloyType,
|
|
293258
|
+
watermark: lineage.watermarkName,
|
|
293259
|
+
...lineage.mergeKeys.length > 0 ? { mergeKeys: lineage.mergeKeys } : {},
|
|
293260
|
+
strategy: lineage.strategy,
|
|
293261
|
+
sourceEntityId: lineage.sourceEntityId
|
|
293262
|
+
}
|
|
293263
|
+
};
|
|
293140
293264
|
}
|
|
293141
293265
|
function connectionMetadataLayers(environment, connectionName) {
|
|
293142
293266
|
try {
|
|
@@ -293279,7 +293403,7 @@ class MaterializationService {
|
|
|
293279
293403
|
const buildInstructions = options.buildInstructions;
|
|
293280
293404
|
const orchestrated = buildInstructions !== undefined;
|
|
293281
293405
|
if (orchestrated) {
|
|
293282
|
-
this.validateInstructions(pkg.getBuildPlan(), buildInstructions);
|
|
293406
|
+
this.validateInstructions(pkg.getBuildPlan(), buildInstructions, options.ledger, options.reseed ?? false);
|
|
293283
293407
|
}
|
|
293284
293408
|
const active2 = await this.repository.getActiveMaterialization(environmentId, packageName);
|
|
293285
293409
|
if (active2) {
|
|
@@ -293310,6 +293434,7 @@ class MaterializationService {
|
|
|
293310
293434
|
forceRefresh,
|
|
293311
293435
|
reseed,
|
|
293312
293436
|
buildInstructions,
|
|
293437
|
+
ledger: orchestrated ? options.ledger : undefined,
|
|
293313
293438
|
referenceManifest: options.referenceManifest,
|
|
293314
293439
|
strictUpstreams: options.strictUpstreams,
|
|
293315
293440
|
trigger,
|
|
@@ -293346,7 +293471,8 @@ class MaterializationService {
|
|
|
293346
293471
|
packageName,
|
|
293347
293472
|
materializationId: id,
|
|
293348
293473
|
forceRefresh: opts.reseed ?? false,
|
|
293349
|
-
now: new Date(startedAt)
|
|
293474
|
+
now: new Date(startedAt),
|
|
293475
|
+
ledger: opts.ledger
|
|
293350
293476
|
});
|
|
293351
293477
|
let instructions;
|
|
293352
293478
|
let carried;
|
|
@@ -293563,7 +293689,7 @@ class MaterializationService {
|
|
|
293563
293689
|
});
|
|
293564
293690
|
}
|
|
293565
293691
|
}
|
|
293566
|
-
validateInstructions(plan, instructions) {
|
|
293692
|
+
validateInstructions(plan, instructions, ledger, runReseed = false) {
|
|
293567
293693
|
if (!plan) {
|
|
293568
293694
|
throw new BadRequestError("Package has no persist sources; buildInstructions cannot be applied");
|
|
293569
293695
|
}
|
|
@@ -293579,6 +293705,41 @@ class MaterializationService {
|
|
|
293579
293705
|
throw new BadRequestError("realization=SNAPSHOT is not supported (COPY only)");
|
|
293580
293706
|
}
|
|
293581
293707
|
}
|
|
293708
|
+
if (ledger === undefined || ledger.length === 0)
|
|
293709
|
+
return;
|
|
293710
|
+
const instructed = new Map;
|
|
293711
|
+
const byAddress = new Map(Object.values(plan.sources).map((s) => [s.sourceEntityId, s]));
|
|
293712
|
+
for (const instruction of instructions) {
|
|
293713
|
+
const planSource = (instruction.sourceID ? plan.sources[instruction.sourceID] : undefined) ?? byAddress.get(instruction.sourceEntityId);
|
|
293714
|
+
if (!planSource)
|
|
293715
|
+
continue;
|
|
293716
|
+
instructed.set(`${planSource.connectionName}\x00${instruction.physicalTableName}`, {
|
|
293717
|
+
sourceEntityId: planSource.sourceEntityId,
|
|
293718
|
+
refresh: planSource.refresh ?? null,
|
|
293719
|
+
reseed: runReseed || instruction.reseed === true
|
|
293720
|
+
});
|
|
293721
|
+
}
|
|
293722
|
+
const seen = new Set;
|
|
293723
|
+
for (const entry of ledger) {
|
|
293724
|
+
const key = `${entry.connectionName}\x00${entry.physicalTableName}`;
|
|
293725
|
+
const table = `'${entry.physicalTableName}' on connection '${entry.connectionName}'`;
|
|
293726
|
+
if (seen.has(key)) {
|
|
293727
|
+
throw new BadRequestError(`Ledger entry for table ${table} appears more than once`);
|
|
293728
|
+
}
|
|
293729
|
+
seen.add(key);
|
|
293730
|
+
const target = instructed.get(key);
|
|
293731
|
+
if (!target) {
|
|
293732
|
+
throw new BadRequestError(`Ledger entry names table ${table}, which this run's ` + `instructions do not build`);
|
|
293733
|
+
}
|
|
293734
|
+
if (target.reseed)
|
|
293735
|
+
continue;
|
|
293736
|
+
if (target.refresh !== "incremental") {
|
|
293737
|
+
throw new BadRequestError(`Ledger entry names table ${table}, whose source does not ` + `declare refresh="incremental"`);
|
|
293738
|
+
}
|
|
293739
|
+
if (entry.sourceEntityId !== target.sourceEntityId) {
|
|
293740
|
+
throw new BadRequestError(`Ledger entry for table ${table} was measured under a ` + `different definition of its source (its sourceEntityId does ` + `not match the plan's) — expected after a publish or ` + `rollback that changed the source. Delete the entry to ` + `rebuild the source, or set reseed.`);
|
|
293741
|
+
}
|
|
293742
|
+
}
|
|
293582
293743
|
}
|
|
293583
293744
|
quoteSeedTablePath(sourceEntityId, physicalTableName, connectionName, connections) {
|
|
293584
293745
|
const connection = connectionName ? connections.get(connectionName) : undefined;
|
|
@@ -293599,7 +293760,13 @@ class MaterializationService {
|
|
|
293599
293760
|
}
|
|
293600
293761
|
if (Object.keys(declarations).length === 0)
|
|
293601
293762
|
return;
|
|
293602
|
-
|
|
293763
|
+
const { ledger, ...rest } = run;
|
|
293764
|
+
return {
|
|
293765
|
+
...rest,
|
|
293766
|
+
declarations,
|
|
293767
|
+
ledger: this.repository,
|
|
293768
|
+
...ledger !== undefined ? { callerLedger: indexCallerLedger(ledger) } : {}
|
|
293769
|
+
};
|
|
293603
293770
|
}
|
|
293604
293771
|
async executeInstructedBuild(compiled, environment, instructions, seedEntries, signal, strict = false, owner, buildMetadata, incremental) {
|
|
293605
293772
|
const { graphs, sources, connectionDigests, connections } = compiled;
|
|
@@ -293850,7 +294017,8 @@ class MaterializationService {
|
|
|
293850
294017
|
physicalTableName,
|
|
293851
294018
|
connectionName: persistSource.connectionName,
|
|
293852
294019
|
realization: instruction.realization,
|
|
293853
|
-
...
|
|
294020
|
+
...ledgerFields(incrementalRefresh?.lineage, seededThrough),
|
|
294021
|
+
...refreshFields(incrementalRefresh ? "full" : undefined),
|
|
293854
294022
|
rowCount: null
|
|
293855
294023
|
};
|
|
293856
294024
|
}
|
|
@@ -293909,7 +294077,8 @@ class MaterializationService {
|
|
|
293909
294077
|
connectionName: persistSource.connectionName,
|
|
293910
294078
|
realization: instruction.realization,
|
|
293911
294079
|
rowCount: null,
|
|
293912
|
-
...
|
|
294080
|
+
...ledgerFields(lineage, step.coveredThrough),
|
|
294081
|
+
...refreshFields(step.mode === "delta" ? "delta" : "none")
|
|
293913
294082
|
};
|
|
293914
294083
|
}
|
|
293915
294084
|
async buildOneSourceIntoStorage(persistSource, instruction, manifest, environment, buildSQL, builtEntries, dependsOnStorageUpstream) {
|
|
@@ -294491,7 +294660,7 @@ var ASSET_EXTENSIONS = new Set([
|
|
|
294491
294660
|
"woff2",
|
|
294492
294661
|
"xlsx"
|
|
294493
294662
|
]);
|
|
294494
|
-
var SPA_OWNED_SEGMENTS = new Set(["pages", "workbook"]);
|
|
294663
|
+
var SPA_OWNED_SEGMENTS = new Set(["data-apps", "pages", "workbook"]);
|
|
294495
294664
|
function extensionOf(segment) {
|
|
294496
294665
|
const dot = segment.lastIndexOf(".");
|
|
294497
294666
|
if (dot <= 0 || dot === segment.length - 1)
|
|
@@ -294803,7 +294972,7 @@ app.get("/environments/:environmentName/packages/:packageName", (req, res, next)
|
|
|
294803
294972
|
res.redirect(308, withRequestQuery(req, canonical));
|
|
294804
294973
|
});
|
|
294805
294974
|
app.get("/environments/:environmentName/packages/:packageName/*", serveFromPackage);
|
|
294806
|
-
var
|
|
294975
|
+
var DATA_APPS_DEPTH_CAP = 3;
|
|
294807
294976
|
var NON_TAG_TEXT_PATTERN = /<!--[\s\S]*?-->|<!--[\s\S]*$|<(script|style|title|textarea)\b[\s\S]*?<\/\1\s*>/gi;
|
|
294808
294977
|
function stripNonTagText(input) {
|
|
294809
294978
|
let current = input;
|
|
@@ -294814,7 +294983,7 @@ function stripNonTagText(input) {
|
|
|
294814
294983
|
} while (current !== previous);
|
|
294815
294984
|
return current;
|
|
294816
294985
|
}
|
|
294817
|
-
async function
|
|
294986
|
+
async function listPackageDataApps(environmentName, packageName, publicRoot) {
|
|
294818
294987
|
const fs11 = await import("fs/promises");
|
|
294819
294988
|
const out = [];
|
|
294820
294989
|
let realPublicRoot;
|
|
@@ -294824,7 +294993,7 @@ async function listPackagePages(environmentName, packageName, publicRoot) {
|
|
|
294824
294993
|
return out;
|
|
294825
294994
|
}
|
|
294826
294995
|
async function walk(dir, depth) {
|
|
294827
|
-
if (depth >
|
|
294996
|
+
if (depth > DATA_APPS_DEPTH_CAP)
|
|
294828
294997
|
return;
|
|
294829
294998
|
let entries;
|
|
294830
294999
|
try {
|
|
@@ -294921,14 +295090,14 @@ try {
|
|
|
294921
295090
|
logger.warn("Failed to register Prometheus metrics endpoint", { error });
|
|
294922
295091
|
}
|
|
294923
295092
|
app.use(drainingGuard);
|
|
294924
|
-
app.get(`${API_PREFIX2}/environments/:environmentName/packages/:packageName/
|
|
295093
|
+
app.get(`${API_PREFIX2}/environments/:environmentName/packages/:packageName/data-apps`, async (req, res) => {
|
|
294925
295094
|
try {
|
|
294926
295095
|
const environment = await environmentStore.getEnvironment(req.params.environmentName, false);
|
|
294927
295096
|
const pkg = await environment.getPackage(req.params.packageName, false);
|
|
294928
|
-
const
|
|
294929
|
-
res.json(
|
|
295097
|
+
const dataApps = await listPackageDataApps(req.params.environmentName, req.params.packageName, path14.join(pkg.getPackagePath(), "public"));
|
|
295098
|
+
res.json(dataApps);
|
|
294930
295099
|
} catch (error) {
|
|
294931
|
-
logger.error("Failed to list package
|
|
295100
|
+
logger.error("Failed to list package data apps", { error });
|
|
294932
295101
|
const { json, status } = internalErrorToHttpError(error);
|
|
294933
295102
|
res.status(status).json(json);
|
|
294934
295103
|
}
|
|
@@ -295442,7 +295611,7 @@ app.post(`${API_PREFIX2}/environments/:environmentName/packages/:packageName/mod
|
|
|
295442
295611
|
queryMetadata: req.body?.queryMetadata,
|
|
295443
295612
|
queryClass: req.body?.queryClass,
|
|
295444
295613
|
versionId: req.body?.versionId
|
|
295445
|
-
});
|
|
295614
|
+
}, readBypassAuthorize(req));
|
|
295446
295615
|
setFilterDeprecationHeaders(res, {
|
|
295447
295616
|
filterParams: req.body.filterParams ?? req.body.sourceFilters,
|
|
295448
295617
|
bypassFilters: req.body.bypassFilters === true ? true : undefined
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{$ as t,j as o,J as a}from"./index-ByceOJbS.js";function s(){const n=t();return o.jsx(a,{onClickEnvironment:n})}export{s as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{F as j,$ as y,N,j as e,a0 as c,a1 as f,G as s,a2 as k,a3 as u,a4 as v,T as o,a5 as t,a6 as l}from"./index-ByceOJbS.js";function b(){const a=j(),n=a["*"],d=y(),{server:p}=N();if(!a.environmentName)return e.jsx("div",{children:e.jsx("h2",{children:"Missing environment name"})});if(!a.packageName)return e.jsx("div",{children:e.jsx("h2",{children:"Missing package name"})});const i={p:3,maxWidth:1200,mx:"auto"};if(n?.startsWith("pages/")&&!n.endsWith(".malloy")&&!n.endsWith(".malloynb")){const h=n.slice(6),g=c({environmentName:a.environmentName,packageName:a.packageName,modelPath:h});return e.jsx(f,{resourceUri:g})}const r=c({environmentName:a.environmentName,packageName:a.packageName,modelPath:n});if(n?.endsWith(".malloy"))return e.jsx(s,{sx:i,children:e.jsx(k,{resourceUri:r,runOnDemand:!0,maxResultSize:512*1024})});if(n?.endsWith(".malloynb"))return e.jsx(s,{sx:i,children:e.jsx(u,{resourceUri:r,maxResultSize:1024*1024,onNavigate:d})});const x=/\.[^./]+$/.test(n??""),m=v({server:p,environmentName:a.environmentName,packageName:a.packageName,path:n??""});return e.jsxs(s,{sx:i,children:[e.jsx(o,{variant:"h6",sx:{fontWeight:600},children:"Nothing to open at this path"}),e.jsxs(o,{variant:"body2",color:"text.secondary",sx:{mt:1},children:[e.jsx(s,{component:"span",sx:{fontFamily:t},children:n})," ","does not name a"," ",e.jsx(s,{component:"span",sx:{fontFamily:t},children:".malloy"})," ","or"," ",e.jsx(s,{component:"span",sx:{fontFamily:t},children:".malloynb"})," ","file in package"," ",e.jsx(s,{component:"span",sx:{fontFamily:t},children:a.packageName}),". This address opens"," ",e.jsx(s,{component:"span",sx:{fontFamily:t},children:".malloy"})," ","and"," ",e.jsx(s,{component:"span",sx:{fontFamily:t},children:".malloynb"})," ","files."]}),x&&e.jsxs(o,{variant:"body2",color:"text.secondary",sx:{mt:1},children:["A file from the package's"," ",e.jsx(s,{component:"span",sx:{fontFamily:t},children:"public/"})," ","directory is served at ",e.jsx(l,{href:m,children:m}),"."]}),e.jsxs(o,{variant:"body2",color:"text.secondary",sx:{mt:1},children:[e.jsxs(l,{href:`/${encodeURIComponent(a.environmentName)}/${encodeURIComponent(a.packageName)}`,children:["Back to ",a.packageName]})," ","lists this package's models, notebooks, and pages."]})]})}export{b as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{aa as o,j as r,ab as s,ac as a,G as n,T as t}from"./index-ByceOJbS.js";function x(){const e=o();return console.error(e),r.jsx(s,{maxWidth:"lg",component:"main",sx:{display:"flex",flexDirection:"column",my:2,gap:0},children:r.jsxs(a,{sx:{m:"auto",flexDirection:"column"},children:[r.jsx(n,{sx:{height:"300px"}}),r.jsx("img",{src:"/error.png"}),r.jsx(t,{variant:"subtitle1",children:"An unexpected error occurred"})]})})}export{x as default};
|