@malloy-publisher/server 0.10.6 → 0.11.0
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 +956 -125
- package/dist/app/assets/{EnvironmentPage-B9Q9ZYYM.js → EnvironmentPage-Dfn26tY2.js} +1 -1
- package/dist/app/assets/{HomePage-CVbXvH7c.js → HomePage-CNuMPINA.js} +1 -1
- package/dist/app/assets/MainPage-DWjs4_e3.js +1 -0
- package/dist/app/assets/ModelPage-GZ6hXGgw.js +2 -0
- package/dist/app/assets/PackagePage-_5vFWxqm.js +1 -0
- package/dist/app/assets/PackageSplatRoute-CTxtXKZO.js +2 -0
- package/dist/app/assets/{RenderedResult-B_sW7neX.es-CFeRQyYD.js → RenderedResult-r3dg2xOJ.es-t-MnqNaH.js} +3 -3
- package/dist/app/assets/{RouteError-BYb6Nj48.js → RouteError-y4xkvszw.js} +1 -1
- package/dist/app/assets/{ThemeEditorPage-CYe_2MfI.js → ThemeEditorPage-BffGFYK5.js} +1 -1
- package/dist/app/assets/ToggleButtonGroup-BfTJg9cJ.js +1 -0
- package/dist/app/assets/documentRoutes-DnpGGXs4.js +1 -0
- package/dist/app/assets/editPageMounted-efTmRdGK.js +2 -0
- package/dist/app/assets/{index-DEj7hnfZ.js → index-CG6r_Zwr.js} +1 -1
- package/dist/app/assets/{index-DWhQwvJR.js → index-CW23I6Cr.js} +1 -1
- package/dist/app/assets/index-D8JKtZm5.js +483 -0
- package/dist/app/assets/{index-3fArIYYK.js → index-g1sInkiO.js} +1 -1
- package/dist/app/assets/{index.es-CMsNTB-h.js → index.es-AXVff-Xr.js} +5 -5
- package/dist/app/assets/usePackageLinkNavigate-DpGlRKnc.js +1 -0
- package/dist/app/assets/usePackageRoute-BUdFd5dP.js +1 -0
- package/dist/app/index.html +1 -1
- package/dist/cpufeatures-gknxfsk5.node +0 -0
- package/dist/instrumentation.mjs +1 -1
- package/dist/package_load_worker.mjs +232 -190
- package/dist/runtime/publisher.js +58 -1
- package/dist/server.mjs +4518 -1138
- package/package.json +1 -1
- package/dist/app/assets/MainPage-D1Fj4Wy1.js +0 -1
- package/dist/app/assets/ModelPage-DmYocpWT.js +0 -2
- package/dist/app/assets/PackagePage-4TwX_ajC.js +0 -1
- package/dist/app/assets/ToggleButtonGroup-b325mGmL.js +0 -1
- package/dist/app/assets/documentRoutes-D_C8snHV.js +0 -1
- package/dist/app/assets/editPageMounted-1X99LP7v.js +0 -2
- package/dist/app/assets/index-CGKV9Dxi.js +0 -483
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{p,r as u}from"./index-D8JKtZm5.js";import{w as c}from"./usePackageRoute-BUdFd5dP.js";function n(t,a,r){const s=p();return u.useCallback((o,i)=>s(c(o,t,a,r),i),[s,t,a,r])}export{n as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{C as f,a9 as m}from"./index-D8JKtZm5.js";const p=/^(latest|[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?)$/,$="latest",l=e=>p.test(e),g=e=>{const n=e.indexOf("/"),o=n===-1?e:e.slice(0,n);if(l(o))return{segment:o,rest:n===-1?"":e.slice(n+1)}},h=e=>e===void 0||e===$?void 0:e,I=(e,n,o)=>`/${encodeURIComponent(e)}/${encodeURIComponent(n)}${o===void 0?"":`/${encodeURIComponent(o)}`}`,E=(e,n,o,t)=>{if(t===void 0)return e;const i=[`/${encodeURIComponent(n)}/${encodeURIComponent(o)}`,`/${n}/${o}`];for(const s of i){if(e!==s&&!e.startsWith(`${s}/`))continue;const r=e.slice(s.length).replace(/^\//,"");return`${I(n,o,t)}${r===""?"":`/${r}`}`}return e};function R(e={}){const n=f(),o=n.environmentName,t=n.packageName,i=n["*"],s=i===void 0?void 0:g(i),{versions:r,isPending:d,isError:v,refetch:u}=m(o??"",t??"",{enabled:e.always===!0||s!==void 0}),a=r.length>0,c=s&&a?s:void 0;return{environmentName:o,packageName:t,versionSegment:c?.segment,versionId:h(c?.segment),path:c?c.rest:i,versioned:a,deciding:s!==void 0&&d,undecided:s!==void 0&&v,retry:u,writable:!a&&!d&&!v}}export{$ as L,I as p,R as u,h as v,E as w};
|
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-D8JKtZm5.js"></script>
|
|
20
20
|
<link rel="stylesheet" crossorigin href="/assets/index-DUqldpo0.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
Binary file
|
package/dist/instrumentation.mjs
CHANGED
|
@@ -164831,7 +164831,7 @@ var init_telemetry = __esm(() => {
|
|
|
164831
164831
|
});
|
|
164832
164832
|
|
|
164833
164833
|
// package.json
|
|
164834
|
-
var version = "0.
|
|
164834
|
+
var version = "0.11.0";
|
|
164835
164835
|
var init_package = () => {};
|
|
164836
164836
|
|
|
164837
164837
|
// src/version.ts
|
|
@@ -12133,6 +12133,14 @@ function logInternalFailure(summary, error, level = "error") {
|
|
|
12133
12133
|
}
|
|
12134
12134
|
});
|
|
12135
12135
|
}
|
|
12136
|
+
function refuseVersionDelete(packageName, versionId, inService, latest, activeCount) {
|
|
12137
|
+
if (latest === versionId) {
|
|
12138
|
+
throw new PackageVersionError("VERSION_IS_LATEST", `Version ${versionId} is the latest version of package ${packageName}; make another version latest before deleting it.`);
|
|
12139
|
+
}
|
|
12140
|
+
if (inService && activeCount <= 1) {
|
|
12141
|
+
throw new PackageVersionError("VERSION_IS_LAST_ACTIVE", `Version ${versionId} is the last version of package ${packageName} in service; delete its archived versions first, or delete the package.`);
|
|
12142
|
+
}
|
|
12143
|
+
}
|
|
12136
12144
|
function filesystemAccessFailure(error) {
|
|
12137
12145
|
let current = error;
|
|
12138
12146
|
for (let depth = 0;depth < 8 && current instanceof Error; depth++) {
|
|
@@ -12202,7 +12210,9 @@ function internalErrorToHttpError(error, { log = true, onLogged } = {}) {
|
|
|
12202
12210
|
logInternal("Filesystem access refused", error, "warn");
|
|
12203
12211
|
return httpError(500, `The server cannot access a path it needs (${describeFilesystemAccessFailure(access)}). ` + `Give the user the server runs as access to it.`);
|
|
12204
12212
|
}
|
|
12205
|
-
if (error instanceof
|
|
12213
|
+
if (error instanceof PackageVersionError) {
|
|
12214
|
+
return httpError(error.status, error.message, error.reason);
|
|
12215
|
+
} else if (error instanceof BadRequestError) {
|
|
12206
12216
|
return httpError(400, error.message);
|
|
12207
12217
|
} else if (error instanceof ServerConfigurationError) {
|
|
12208
12218
|
logInternal("Server configuration error", error, "warn");
|
|
@@ -12260,6 +12270,8 @@ function internalErrorToHttpError(error, { log = true, onLogged } = {}) {
|
|
|
12260
12270
|
return httpError(422, error.message);
|
|
12261
12271
|
} else if (error instanceof ModelCompilationError) {
|
|
12262
12272
|
return httpError(424, error.message);
|
|
12273
|
+
} else if (error instanceof VersionFilesMissingError) {
|
|
12274
|
+
return httpError(424, error.message);
|
|
12263
12275
|
} else if (error instanceof PackageManifestError) {
|
|
12264
12276
|
return httpError(424, error.message);
|
|
12265
12277
|
} else if (error instanceof ConnectionError) {
|
|
@@ -12311,12 +12323,36 @@ function toQueryTextProblem(problem) {
|
|
|
12311
12323
|
...problem.at ? { at: { range: problem.at.range } } : {}
|
|
12312
12324
|
};
|
|
12313
12325
|
}
|
|
12314
|
-
var GENERIC_INTERNAL_MESSAGE = "Internal server error.", GENERIC_UPSTREAM_MESSAGE = "Upstream connection error.", GENERIC_UNREACHABLE_MESSAGE = "The database connection is down: the database could not be reached, so the query did not run.", GENERIC_AUTH_MESSAGE = "The database rejected the connection's credentials. Check the connection's user, password, key or token.", MAX_LOGGED_DETAIL_CHARS = 2000, FILESYSTEM_ACCESS_DESCRIPTIONS, POSTGRES_STATEMENT_SQLSTATES, POSTGRES_UNDEFINED_TABLE = "42P01", POSTGRES_RELATION_MISSING, NotImplementedError, BadRequestError, InvalidArgumentError, CompileRefusedError, InvalidModelPathError, RenderTagRefusedError, UnparseableTextError, EnvironmentNotFoundError, PackageNotFoundError, ModelNotFoundError, DashboardNotFoundError, SkillNotFoundError, AgentNotFoundError, ConflictError, ConnectionNotFoundError, TableNotFoundError, ConnectionError, ConnectionFailedError, UnconfiguredConnectionError, ConnectionPoolExhaustedError, DestinationNotFoundError, StorageDestinationNotFoundError, StorageCatalogNotFoundError, ConnectionAuthError, UnsupportedCatalogFormatError, ModelCompilationError, PackageManifestError, MaterializationEligibilityError, ChainedUpstreamMissingError, ChainedShapeNotCarriedError, PublisherConfigError, ServerConfigurationError, FrozenConfigError, AccessDeniedError, QueryCompileError, NotQueryableError, OffSurfaceError, MaterializationNotFoundError, MaterializationConflictError, WriteConflictError, WriteRolledBackError, WriteRollbackFailedError, WriteVerifyError, InvalidStateTransitionError, ServiceUnavailableError, PackageAdmissionRefusedError, PayloadTooLargeError, ResponseUnserializableError, QueryTimeoutError;
|
|
12326
|
+
var GENERIC_INTERNAL_MESSAGE = "Internal server error.", GENERIC_UPSTREAM_MESSAGE = "Upstream connection error.", GENERIC_UNREACHABLE_MESSAGE = "The database connection is down: the database could not be reached, so the query did not run.", GENERIC_AUTH_MESSAGE = "The database rejected the connection's credentials. Check the connection's user, password, key or token.", MAX_LOGGED_DETAIL_CHARS = 2000, PACKAGE_VERSION_ERROR_STATUS, PackageVersionError, FILESYSTEM_ACCESS_DESCRIPTIONS, POSTGRES_STATEMENT_SQLSTATES, POSTGRES_UNDEFINED_TABLE = "42P01", POSTGRES_RELATION_MISSING, NotImplementedError, BadRequestError, InvalidArgumentError, CompileRefusedError, InvalidModelPathError, RenderTagRefusedError, UnparseableTextError, EnvironmentNotFoundError, PackageNotFoundError, ModelNotFoundError, DashboardNotFoundError, SkillNotFoundError, AgentNotFoundError, ConflictError, ConnectionNotFoundError, TableNotFoundError, ConnectionError, ConnectionFailedError, UnconfiguredConnectionError, ConnectionPoolExhaustedError, DestinationNotFoundError, StorageDestinationNotFoundError, StorageCatalogNotFoundError, ConnectionAuthError, UnsupportedCatalogFormatError, ModelCompilationError, VersionFilesMissingError, PackageManifestError, MaterializationEligibilityError, ChainedUpstreamMissingError, ChainedShapeNotCarriedError, PublisherConfigError, ServerConfigurationError, FrozenConfigError, AccessDeniedError, QueryCompileError, NotQueryableError, OffSurfaceError, MaterializationNotFoundError, MaterializationConflictError, WriteConflictError, WriteRolledBackError, WriteRollbackFailedError, WriteVerifyError, InvalidStateTransitionError, ServiceUnavailableError, PackageAdmissionRefusedError, PayloadTooLargeError, ResponseUnserializableError, QueryTimeoutError;
|
|
12315
12327
|
var init_errors = __esm(() => {
|
|
12316
12328
|
init_constants();
|
|
12317
12329
|
init_logger();
|
|
12318
12330
|
init_driver_errors();
|
|
12319
12331
|
init_pg_helpers();
|
|
12332
|
+
PACKAGE_VERSION_ERROR_STATUS = {
|
|
12333
|
+
MANIFEST_VERSION_MISSING: 400,
|
|
12334
|
+
MANIFEST_VERSION_INVALID: 400,
|
|
12335
|
+
VERSION_ID_INVALID: 400,
|
|
12336
|
+
VERSION_NOT_FOUND: 404,
|
|
12337
|
+
VERSION_CONFLICT: 409,
|
|
12338
|
+
PACKAGE_IS_VERSIONED: 409,
|
|
12339
|
+
VERSION_IS_LATEST: 409,
|
|
12340
|
+
VERSION_IS_LAST_ACTIVE: 409,
|
|
12341
|
+
VERSION_BUILDING: 409,
|
|
12342
|
+
VERSION_NOT_LATEST: 400,
|
|
12343
|
+
VERSION_ARCHIVED: 410
|
|
12344
|
+
};
|
|
12345
|
+
PackageVersionError = class PackageVersionError extends Error {
|
|
12346
|
+
reason;
|
|
12347
|
+
constructor(reason, message) {
|
|
12348
|
+
super(message);
|
|
12349
|
+
this.reason = reason;
|
|
12350
|
+
this.name = "PackageVersionError";
|
|
12351
|
+
}
|
|
12352
|
+
get status() {
|
|
12353
|
+
return PACKAGE_VERSION_ERROR_STATUS[this.reason];
|
|
12354
|
+
}
|
|
12355
|
+
};
|
|
12320
12356
|
FILESYSTEM_ACCESS_DESCRIPTIONS = {
|
|
12321
12357
|
EACCES: "permission denied",
|
|
12322
12358
|
EPERM: "operation not permitted",
|
|
@@ -12471,6 +12507,12 @@ var init_errors = __esm(() => {
|
|
|
12471
12507
|
super(error.message);
|
|
12472
12508
|
}
|
|
12473
12509
|
};
|
|
12510
|
+
VersionFilesMissingError = class VersionFilesMissingError extends Error {
|
|
12511
|
+
constructor(message) {
|
|
12512
|
+
super(message);
|
|
12513
|
+
this.name = "VersionFilesMissingError";
|
|
12514
|
+
}
|
|
12515
|
+
};
|
|
12474
12516
|
PackageManifestError = class PackageManifestError extends Error {
|
|
12475
12517
|
constructor(message) {
|
|
12476
12518
|
super(message);
|
|
@@ -14203,6 +14245,189 @@ var init_package_revision = __esm(() => {
|
|
|
14203
14245
|
MANIFEST_AGENTS_MAX_BYTES = 1024 * 1024;
|
|
14204
14246
|
});
|
|
14205
14247
|
|
|
14248
|
+
// src/service/package_manifest.ts
|
|
14249
|
+
function parsePackageScope(raw) {
|
|
14250
|
+
if (raw === undefined || raw === null) {
|
|
14251
|
+
return "package";
|
|
14252
|
+
}
|
|
14253
|
+
if (PACKAGE_SCOPES.includes(raw)) {
|
|
14254
|
+
return raw;
|
|
14255
|
+
}
|
|
14256
|
+
throw new PackageManifestError(`Invalid "scope" in the package manifest: ${JSON.stringify(raw)}. ` + `Expected "version" or "package" (default "package").`);
|
|
14257
|
+
}
|
|
14258
|
+
function resolvePackageScope(rootRaw, materializationRaw) {
|
|
14259
|
+
const envelopeRaw = materializationRaw && typeof materializationRaw === "object" ? materializationRaw.scope : undefined;
|
|
14260
|
+
const rootDeclared = rootRaw !== undefined && rootRaw !== null;
|
|
14261
|
+
const envelopeDeclared = envelopeRaw !== undefined && envelopeRaw !== null;
|
|
14262
|
+
const rootScope = parsePackageScope(rootRaw);
|
|
14263
|
+
const envelopeScope = parsePackageScope(envelopeRaw);
|
|
14264
|
+
if (rootDeclared && envelopeDeclared) {
|
|
14265
|
+
if (rootScope !== envelopeScope) {
|
|
14266
|
+
throw new PackageManifestError(`Conflicting "scope" in publisher.json: root "${rootScope}" vs ` + `"materialization.scope" "${envelopeScope}". The package cannot ` + `load until they agree. Edit "materialization": { "scope": ... } ` + `to the value you want and delete the root-level "scope" (the ` + `server rewrites both homes on its next manifest write).`);
|
|
14267
|
+
}
|
|
14268
|
+
return { scope: envelopeScope, warnings: [] };
|
|
14269
|
+
}
|
|
14270
|
+
if (rootDeclared) {
|
|
14271
|
+
return { scope: rootScope, warnings: [SCOPE_ROOT_DEPRECATION] };
|
|
14272
|
+
}
|
|
14273
|
+
return { scope: envelopeScope, warnings: [] };
|
|
14274
|
+
}
|
|
14275
|
+
function resolvePackageQueryMetadata(rootRaw, materializationRaw) {
|
|
14276
|
+
const envelopeRaw = materializationRaw && typeof materializationRaw === "object" ? materializationRaw.queryMetadata : undefined;
|
|
14277
|
+
const rootDeclared = rootRaw !== undefined && rootRaw !== null;
|
|
14278
|
+
const envelopeDeclared = envelopeRaw !== undefined && envelopeRaw !== null;
|
|
14279
|
+
if (rootDeclared && envelopeDeclared) {
|
|
14280
|
+
if (sameQueryMetadataBag(rootRaw, envelopeRaw)) {
|
|
14281
|
+
return { queryMetadata: rootRaw, home: "root", warnings: [] };
|
|
14282
|
+
}
|
|
14283
|
+
return {
|
|
14284
|
+
queryMetadata: rootRaw,
|
|
14285
|
+
home: "root",
|
|
14286
|
+
warnings: [QUERY_METADATA_CONFLICT]
|
|
14287
|
+
};
|
|
14288
|
+
}
|
|
14289
|
+
if (envelopeDeclared) {
|
|
14290
|
+
return {
|
|
14291
|
+
queryMetadata: envelopeRaw,
|
|
14292
|
+
home: "envelope",
|
|
14293
|
+
warnings: [QUERY_METADATA_ENVELOPE_DEPRECATION]
|
|
14294
|
+
};
|
|
14295
|
+
}
|
|
14296
|
+
return { queryMetadata: rootRaw, home: "root", warnings: [] };
|
|
14297
|
+
}
|
|
14298
|
+
function sameQueryMetadataBag(a, b) {
|
|
14299
|
+
return keySortedJson(a) === keySortedJson(b);
|
|
14300
|
+
}
|
|
14301
|
+
function keySortedJson(value) {
|
|
14302
|
+
if (value === null || typeof value !== "object") {
|
|
14303
|
+
return JSON.stringify(value) ?? "undefined";
|
|
14304
|
+
}
|
|
14305
|
+
if (Array.isArray(value)) {
|
|
14306
|
+
return `[${value.map(keySortedJson).join(",")}]`;
|
|
14307
|
+
}
|
|
14308
|
+
const entries = Object.entries(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
14309
|
+
return `{${entries.map(([name, nested]) => `${JSON.stringify(name)}:${keySortedJson(nested)}`).join(",")}}`;
|
|
14310
|
+
}
|
|
14311
|
+
function parseFreshness(raw) {
|
|
14312
|
+
if (!raw || typeof raw !== "object") {
|
|
14313
|
+
return null;
|
|
14314
|
+
}
|
|
14315
|
+
const { window: window2, fallback } = raw;
|
|
14316
|
+
const freshness = {};
|
|
14317
|
+
if (typeof window2 === "string") {
|
|
14318
|
+
freshness.window = window2;
|
|
14319
|
+
}
|
|
14320
|
+
if (typeof fallback === "string" && FRESHNESS_FALLBACKS.includes(fallback)) {
|
|
14321
|
+
freshness.fallback = fallback;
|
|
14322
|
+
}
|
|
14323
|
+
return freshness;
|
|
14324
|
+
}
|
|
14325
|
+
function parseQueryMetadata(raw, label = QUERY_METADATA_HOME_LABELS.envelope) {
|
|
14326
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
14327
|
+
return { metadata: null, warnings: [] };
|
|
14328
|
+
}
|
|
14329
|
+
const out = {};
|
|
14330
|
+
const warnings = [];
|
|
14331
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
14332
|
+
if (typeof value === "string") {
|
|
14333
|
+
out[name] = value;
|
|
14334
|
+
} else {
|
|
14335
|
+
warnings.push(`${label}: property '${name}' must be a ` + `string (got ${value === null ? "null" : typeof value}); it is ` + `not attached to any statement`);
|
|
14336
|
+
}
|
|
14337
|
+
}
|
|
14338
|
+
return {
|
|
14339
|
+
metadata: Object.keys(out).length > 0 ? out : null,
|
|
14340
|
+
warnings
|
|
14341
|
+
};
|
|
14342
|
+
}
|
|
14343
|
+
function parsePackageMaterialization(raw) {
|
|
14344
|
+
if (!raw || typeof raw !== "object") {
|
|
14345
|
+
return null;
|
|
14346
|
+
}
|
|
14347
|
+
const { schedule, freshness, queryMetadata } = raw;
|
|
14348
|
+
return {
|
|
14349
|
+
schedule: typeof schedule === "string" ? schedule : null,
|
|
14350
|
+
freshness: parseFreshness(freshness),
|
|
14351
|
+
queryMetadata: parseQueryMetadata(queryMetadata).metadata
|
|
14352
|
+
};
|
|
14353
|
+
}
|
|
14354
|
+
function materializationWithQueryMetadata(parsed, queryMetadataRaw) {
|
|
14355
|
+
const queryMetadata = parseQueryMetadata(queryMetadataRaw).metadata;
|
|
14356
|
+
if (!parsed && !queryMetadata)
|
|
14357
|
+
return null;
|
|
14358
|
+
return {
|
|
14359
|
+
schedule: parsed?.schedule ?? null,
|
|
14360
|
+
freshness: parsed?.freshness ?? null,
|
|
14361
|
+
queryMetadata
|
|
14362
|
+
};
|
|
14363
|
+
}
|
|
14364
|
+
function queryMetadataParseWarnings(raw, home = "root") {
|
|
14365
|
+
return parseQueryMetadata(raw, QUERY_METADATA_HOME_LABELS[home]).warnings;
|
|
14366
|
+
}
|
|
14367
|
+
function resolveExplores(input) {
|
|
14368
|
+
const { declaredExplores, declaredQueryableSources, modelPaths } = input;
|
|
14369
|
+
const reportPaths = input.reportPaths ?? new Set;
|
|
14370
|
+
const hasIndexModel = modelPaths.includes(INDEX_MODEL_NAME);
|
|
14371
|
+
const warnings = [];
|
|
14372
|
+
if (declaredExplores !== undefined && !(Array.isArray(declaredExplores) && declaredExplores.every((entry) => typeof entry === "string"))) {
|
|
14373
|
+
throw new PackageManifestError(`Invalid "explores" in publisher.json: it must be a list of file ` + `names, but is ${JSON.stringify(declaredExplores)}. The package ` + `was not loaded. Fix: delete "explores" and add an ` + `${INDEX_MODEL_NAME}.`);
|
|
14374
|
+
}
|
|
14375
|
+
const declared = Array.isArray(declaredExplores) ? declaredExplores.map((entry) => normalizeModelPath(entry)) : undefined;
|
|
14376
|
+
if (declaredQueryableSources !== undefined && declaredQueryableSources !== "all") {
|
|
14377
|
+
warnings.push(QUERYABLE_SOURCES_DEPRECATION);
|
|
14378
|
+
}
|
|
14379
|
+
if (declared !== undefined) {
|
|
14380
|
+
if (declared.length === 0) {
|
|
14381
|
+
warnings.push(hasIndexModel ? EXPLORES_EMPTY_SUPPRESSES_CONVENTION : EXPLORES_EMPTY_IS_UNCURATED);
|
|
14382
|
+
} else {
|
|
14383
|
+
warnings.push(exploresDeprecation(declared, hasIndexModel, reportPaths));
|
|
14384
|
+
}
|
|
14385
|
+
if (hasIndexModel && declared.length > 0 && !declared.includes(INDEX_MODEL_NAME)) {
|
|
14386
|
+
warnings.push(EXPLORES_OMITS_INDEX_MODEL);
|
|
14387
|
+
}
|
|
14388
|
+
return { explores: declared, warnings };
|
|
14389
|
+
}
|
|
14390
|
+
if (!hasIndexModel) {
|
|
14391
|
+
for (const modelPath of modelPaths) {
|
|
14392
|
+
if (!modelPath.includes("/") && modelPath.toLowerCase() === INDEX_MODEL_NAME) {
|
|
14393
|
+
warnings.push(`${modelPath} is ignored: only a root file named exactly ` + `${INDEX_MODEL_NAME} decides what is published. Fix: rename ` + `it to ${INDEX_MODEL_NAME}.`);
|
|
14394
|
+
}
|
|
14395
|
+
}
|
|
14396
|
+
return { explores: undefined, warnings };
|
|
14397
|
+
}
|
|
14398
|
+
return { explores: [INDEX_MODEL_NAME], warnings };
|
|
14399
|
+
}
|
|
14400
|
+
function listFiles(files) {
|
|
14401
|
+
return files.length <= 1 ? files[0] ?? "" : `${files.slice(0, -1).join(", ")} and ${files[files.length - 1]}`;
|
|
14402
|
+
}
|
|
14403
|
+
function exploresDeprecation(declared, hasIndexModel, reportPaths) {
|
|
14404
|
+
const lead = `"explores" in publisher.json is deprecated.`;
|
|
14405
|
+
const files = declared.filter((entry) => entry !== INDEX_MODEL_NAME && !reportPaths.has(entry));
|
|
14406
|
+
if (files.length > 0) {
|
|
14407
|
+
return hasIndexModel ? `${lead} Fix: import ${listFiles(files)} into ${INDEX_MODEL_NAME}, ` + `export the sources you publish from it, then delete "explores".` : `${lead} Fix: add an ${INDEX_MODEL_NAME} at the package root that ` + `imports ${listFiles(files)} and exports the sources you want to ` + `publish, then delete "explores".`;
|
|
14408
|
+
}
|
|
14409
|
+
if (declared.includes(INDEX_MODEL_NAME)) {
|
|
14410
|
+
return `${lead} ${INDEX_MODEL_NAME} already publishes the same thing. ` + `Fix: delete "explores".`;
|
|
14411
|
+
}
|
|
14412
|
+
return hasIndexModel ? `${lead} Fix: delete "explores", so ${INDEX_MODEL_NAME} decides what is published.` : `${lead} Fix: add an ${INDEX_MODEL_NAME} at the package root that ` + `exports the sources you want to publish, then delete "explores".`;
|
|
14413
|
+
}
|
|
14414
|
+
var FRESHNESS_FALLBACKS, PACKAGE_SCOPES, SCOPE_ROOT_DEPRECATION, QUERY_METADATA_HOME_LABELS, QUERY_METADATA_ENVELOPE_DEPRECATION, QUERY_METADATA_CONFLICT, EXPLORES_OMITS_INDEX_MODEL, EXPLORES_EMPTY_SUPPRESSES_CONVENTION, EXPLORES_EMPTY_IS_UNCURATED = `"explores": [] in publisher.json does nothing. Fix: delete it.`, QUERYABLE_SOURCES_DEPRECATION = `"queryableSources" in publisher.json does nothing. Fix: delete it.`;
|
|
14415
|
+
var init_package_manifest = __esm(() => {
|
|
14416
|
+
init_constants();
|
|
14417
|
+
init_errors();
|
|
14418
|
+
FRESHNESS_FALLBACKS = ["live", "stale_ok", "fail"];
|
|
14419
|
+
PACKAGE_SCOPES = ["version", "package"];
|
|
14420
|
+
SCOPE_ROOT_DEPRECATION = `"scope" at the manifest root is deprecated: declare it as ` + `"materialization": { "scope": ... } alongside the other build knobs. The ` + `root form still works and will be removed in a future release; until then ` + `the server keeps both homes in sync when it writes the manifest, so an ` + `older publisher still reads the right value.`;
|
|
14421
|
+
QUERY_METADATA_HOME_LABELS = {
|
|
14422
|
+
root: "queryMetadata",
|
|
14423
|
+
envelope: "materialization.queryMetadata"
|
|
14424
|
+
};
|
|
14425
|
+
QUERY_METADATA_ENVELOPE_DEPRECATION = `"queryMetadata" inside "materialization" is deprecated: declare it at the ` + `manifest root instead. It is not a build setting — the properties ride ` + `every statement the package's sources issue, including served queries. The ` + `enveloped form still works and will be removed in a future release; until ` + `then the server keeps both homes in sync when it writes the manifest, so an ` + `older publisher still reads the right value.`;
|
|
14426
|
+
QUERY_METADATA_CONFLICT = `Conflicting "queryMetadata" in publisher.json: the manifest root and ` + `"materialization.queryMetadata" declare different bags, and the root wins. ` + `Delete "materialization": { "queryMetadata": ... } — the server rewrites ` + `both homes on its next manifest write, so an older publisher still reads ` + `the right value.`;
|
|
14427
|
+
EXPLORES_OMITS_INDEX_MODEL = `${INDEX_MODEL_NAME} is ignored because "explores" in publisher.json ` + `doesn't list it. Fix: delete "explores" to publish what ` + `${INDEX_MODEL_NAME} exports, or rename ${INDEX_MODEL_NAME} (and any import ` + `of it) if it isn't meant to decide what is published.`;
|
|
14428
|
+
EXPLORES_EMPTY_SUPPRESSES_CONVENTION = `"explores" in publisher.json is deprecated. Here it stops ` + `${INDEX_MODEL_NAME} from limiting what this package publishes. Fix: to ` + `publish everything, rename ${INDEX_MODEL_NAME}, point any import of it at ` + `the new name, then delete "explores".`;
|
|
14429
|
+
});
|
|
14430
|
+
|
|
14206
14431
|
// src/service/package_retrieval.ts
|
|
14207
14432
|
import { createHash as createHash2 } from "crypto";
|
|
14208
14433
|
import * as fs2 from "fs";
|
|
@@ -23652,6 +23877,11 @@ init_gate_classification();
|
|
|
23652
23877
|
init_gate_dimension();
|
|
23653
23878
|
init_model_info();
|
|
23654
23879
|
init_package_revision();
|
|
23880
|
+
init_package_manifest();
|
|
23881
|
+
init_package_retrieval();
|
|
23882
|
+
init_source_extraction();
|
|
23883
|
+
init_given();
|
|
23884
|
+
init_utils();
|
|
23655
23885
|
var import_recursive_readdir = __toESM(require_recursive_readdir(), 1);
|
|
23656
23886
|
import {
|
|
23657
23887
|
contextOverlay,
|
|
@@ -23666,194 +23896,6 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
23666
23896
|
import { parentPort, threadId, workerData } from "node:worker_threads";
|
|
23667
23897
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
23668
23898
|
|
|
23669
|
-
// src/service/package_manifest.ts
|
|
23670
|
-
init_constants();
|
|
23671
|
-
init_errors();
|
|
23672
|
-
var FRESHNESS_FALLBACKS = ["live", "stale_ok", "fail"];
|
|
23673
|
-
var PACKAGE_SCOPES = ["version", "package"];
|
|
23674
|
-
function parsePackageScope(raw) {
|
|
23675
|
-
if (raw === undefined || raw === null) {
|
|
23676
|
-
return "package";
|
|
23677
|
-
}
|
|
23678
|
-
if (PACKAGE_SCOPES.includes(raw)) {
|
|
23679
|
-
return raw;
|
|
23680
|
-
}
|
|
23681
|
-
throw new PackageManifestError(`Invalid "scope" in the package manifest: ${JSON.stringify(raw)}. ` + `Expected "version" or "package" (default "package").`);
|
|
23682
|
-
}
|
|
23683
|
-
function resolvePackageScope(rootRaw, materializationRaw) {
|
|
23684
|
-
const envelopeRaw = materializationRaw && typeof materializationRaw === "object" ? materializationRaw.scope : undefined;
|
|
23685
|
-
const rootDeclared = rootRaw !== undefined && rootRaw !== null;
|
|
23686
|
-
const envelopeDeclared = envelopeRaw !== undefined && envelopeRaw !== null;
|
|
23687
|
-
const rootScope = parsePackageScope(rootRaw);
|
|
23688
|
-
const envelopeScope = parsePackageScope(envelopeRaw);
|
|
23689
|
-
if (rootDeclared && envelopeDeclared) {
|
|
23690
|
-
if (rootScope !== envelopeScope) {
|
|
23691
|
-
throw new PackageManifestError(`Conflicting "scope" in publisher.json: root "${rootScope}" vs ` + `"materialization.scope" "${envelopeScope}". The package cannot ` + `load until they agree. Edit "materialization": { "scope": ... } ` + `to the value you want and delete the root-level "scope" (the ` + `server rewrites both homes on its next manifest write).`);
|
|
23692
|
-
}
|
|
23693
|
-
return { scope: envelopeScope, warnings: [] };
|
|
23694
|
-
}
|
|
23695
|
-
if (rootDeclared) {
|
|
23696
|
-
return { scope: rootScope, warnings: [SCOPE_ROOT_DEPRECATION] };
|
|
23697
|
-
}
|
|
23698
|
-
return { scope: envelopeScope, warnings: [] };
|
|
23699
|
-
}
|
|
23700
|
-
var SCOPE_ROOT_DEPRECATION = `"scope" at the manifest root is deprecated: declare it as ` + `"materialization": { "scope": ... } alongside the other build knobs. The ` + `root form still works and will be removed in a future release; until then ` + `the server keeps both homes in sync when it writes the manifest, so an ` + `older publisher still reads the right value.`;
|
|
23701
|
-
function resolvePackageQueryMetadata(rootRaw, materializationRaw) {
|
|
23702
|
-
const envelopeRaw = materializationRaw && typeof materializationRaw === "object" ? materializationRaw.queryMetadata : undefined;
|
|
23703
|
-
const rootDeclared = rootRaw !== undefined && rootRaw !== null;
|
|
23704
|
-
const envelopeDeclared = envelopeRaw !== undefined && envelopeRaw !== null;
|
|
23705
|
-
if (rootDeclared && envelopeDeclared) {
|
|
23706
|
-
if (sameQueryMetadataBag(rootRaw, envelopeRaw)) {
|
|
23707
|
-
return { queryMetadata: rootRaw, home: "root", warnings: [] };
|
|
23708
|
-
}
|
|
23709
|
-
return {
|
|
23710
|
-
queryMetadata: rootRaw,
|
|
23711
|
-
home: "root",
|
|
23712
|
-
warnings: [QUERY_METADATA_CONFLICT]
|
|
23713
|
-
};
|
|
23714
|
-
}
|
|
23715
|
-
if (envelopeDeclared) {
|
|
23716
|
-
return {
|
|
23717
|
-
queryMetadata: envelopeRaw,
|
|
23718
|
-
home: "envelope",
|
|
23719
|
-
warnings: [QUERY_METADATA_ENVELOPE_DEPRECATION]
|
|
23720
|
-
};
|
|
23721
|
-
}
|
|
23722
|
-
return { queryMetadata: rootRaw, home: "root", warnings: [] };
|
|
23723
|
-
}
|
|
23724
|
-
function sameQueryMetadataBag(a, b) {
|
|
23725
|
-
return keySortedJson(a) === keySortedJson(b);
|
|
23726
|
-
}
|
|
23727
|
-
function keySortedJson(value) {
|
|
23728
|
-
if (value === null || typeof value !== "object") {
|
|
23729
|
-
return JSON.stringify(value) ?? "undefined";
|
|
23730
|
-
}
|
|
23731
|
-
if (Array.isArray(value)) {
|
|
23732
|
-
return `[${value.map(keySortedJson).join(",")}]`;
|
|
23733
|
-
}
|
|
23734
|
-
const entries = Object.entries(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
23735
|
-
return `{${entries.map(([name, nested]) => `${JSON.stringify(name)}:${keySortedJson(nested)}`).join(",")}}`;
|
|
23736
|
-
}
|
|
23737
|
-
var QUERY_METADATA_HOME_LABELS = {
|
|
23738
|
-
root: "queryMetadata",
|
|
23739
|
-
envelope: "materialization.queryMetadata"
|
|
23740
|
-
};
|
|
23741
|
-
var QUERY_METADATA_ENVELOPE_DEPRECATION = `"queryMetadata" inside "materialization" is deprecated: declare it at the ` + `manifest root instead. It is not a build setting — the properties ride ` + `every statement the package's sources issue, including served queries. The ` + `enveloped form still works and will be removed in a future release; until ` + `then the server keeps both homes in sync when it writes the manifest, so an ` + `older publisher still reads the right value.`;
|
|
23742
|
-
var QUERY_METADATA_CONFLICT = `Conflicting "queryMetadata" in publisher.json: the manifest root and ` + `"materialization.queryMetadata" declare different bags, and the root wins. ` + `Delete "materialization": { "queryMetadata": ... } — the server rewrites ` + `both homes on its next manifest write, so an older publisher still reads ` + `the right value.`;
|
|
23743
|
-
function parseFreshness(raw) {
|
|
23744
|
-
if (!raw || typeof raw !== "object") {
|
|
23745
|
-
return null;
|
|
23746
|
-
}
|
|
23747
|
-
const { window: window2, fallback } = raw;
|
|
23748
|
-
const freshness = {};
|
|
23749
|
-
if (typeof window2 === "string") {
|
|
23750
|
-
freshness.window = window2;
|
|
23751
|
-
}
|
|
23752
|
-
if (typeof fallback === "string" && FRESHNESS_FALLBACKS.includes(fallback)) {
|
|
23753
|
-
freshness.fallback = fallback;
|
|
23754
|
-
}
|
|
23755
|
-
return freshness;
|
|
23756
|
-
}
|
|
23757
|
-
function parseQueryMetadata(raw, label = QUERY_METADATA_HOME_LABELS.envelope) {
|
|
23758
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
23759
|
-
return { metadata: null, warnings: [] };
|
|
23760
|
-
}
|
|
23761
|
-
const out = {};
|
|
23762
|
-
const warnings = [];
|
|
23763
|
-
for (const [name, value] of Object.entries(raw)) {
|
|
23764
|
-
if (typeof value === "string") {
|
|
23765
|
-
out[name] = value;
|
|
23766
|
-
} else {
|
|
23767
|
-
warnings.push(`${label}: property '${name}' must be a ` + `string (got ${value === null ? "null" : typeof value}); it is ` + `not attached to any statement`);
|
|
23768
|
-
}
|
|
23769
|
-
}
|
|
23770
|
-
return {
|
|
23771
|
-
metadata: Object.keys(out).length > 0 ? out : null,
|
|
23772
|
-
warnings
|
|
23773
|
-
};
|
|
23774
|
-
}
|
|
23775
|
-
function parsePackageMaterialization(raw) {
|
|
23776
|
-
if (!raw || typeof raw !== "object") {
|
|
23777
|
-
return null;
|
|
23778
|
-
}
|
|
23779
|
-
const { schedule, freshness, queryMetadata } = raw;
|
|
23780
|
-
return {
|
|
23781
|
-
schedule: typeof schedule === "string" ? schedule : null,
|
|
23782
|
-
freshness: parseFreshness(freshness),
|
|
23783
|
-
queryMetadata: parseQueryMetadata(queryMetadata).metadata
|
|
23784
|
-
};
|
|
23785
|
-
}
|
|
23786
|
-
function materializationWithQueryMetadata(parsed, queryMetadataRaw) {
|
|
23787
|
-
const queryMetadata = parseQueryMetadata(queryMetadataRaw).metadata;
|
|
23788
|
-
if (!parsed && !queryMetadata)
|
|
23789
|
-
return null;
|
|
23790
|
-
return {
|
|
23791
|
-
schedule: parsed?.schedule ?? null,
|
|
23792
|
-
freshness: parsed?.freshness ?? null,
|
|
23793
|
-
queryMetadata
|
|
23794
|
-
};
|
|
23795
|
-
}
|
|
23796
|
-
function queryMetadataParseWarnings(raw, home = "root") {
|
|
23797
|
-
return parseQueryMetadata(raw, QUERY_METADATA_HOME_LABELS[home]).warnings;
|
|
23798
|
-
}
|
|
23799
|
-
function resolveExplores(input) {
|
|
23800
|
-
const { declaredExplores, declaredQueryableSources, modelPaths } = input;
|
|
23801
|
-
const reportPaths = input.reportPaths ?? new Set;
|
|
23802
|
-
const hasIndexModel = modelPaths.includes(INDEX_MODEL_NAME);
|
|
23803
|
-
const warnings = [];
|
|
23804
|
-
if (declaredExplores !== undefined && !(Array.isArray(declaredExplores) && declaredExplores.every((entry) => typeof entry === "string"))) {
|
|
23805
|
-
throw new PackageManifestError(`Invalid "explores" in publisher.json: it must be a list of file ` + `names, but is ${JSON.stringify(declaredExplores)}. The package ` + `was not loaded. Fix: delete "explores" and add an ` + `${INDEX_MODEL_NAME}.`);
|
|
23806
|
-
}
|
|
23807
|
-
const declared = Array.isArray(declaredExplores) ? declaredExplores.map((entry) => normalizeModelPath(entry)) : undefined;
|
|
23808
|
-
if (declaredQueryableSources !== undefined && declaredQueryableSources !== "all") {
|
|
23809
|
-
warnings.push(QUERYABLE_SOURCES_DEPRECATION);
|
|
23810
|
-
}
|
|
23811
|
-
if (declared !== undefined) {
|
|
23812
|
-
if (declared.length === 0) {
|
|
23813
|
-
warnings.push(hasIndexModel ? EXPLORES_EMPTY_SUPPRESSES_CONVENTION : EXPLORES_EMPTY_IS_UNCURATED);
|
|
23814
|
-
} else {
|
|
23815
|
-
warnings.push(exploresDeprecation(declared, hasIndexModel, reportPaths));
|
|
23816
|
-
}
|
|
23817
|
-
if (hasIndexModel && declared.length > 0 && !declared.includes(INDEX_MODEL_NAME)) {
|
|
23818
|
-
warnings.push(EXPLORES_OMITS_INDEX_MODEL);
|
|
23819
|
-
}
|
|
23820
|
-
return { explores: declared, warnings };
|
|
23821
|
-
}
|
|
23822
|
-
if (!hasIndexModel) {
|
|
23823
|
-
for (const modelPath of modelPaths) {
|
|
23824
|
-
if (!modelPath.includes("/") && modelPath.toLowerCase() === INDEX_MODEL_NAME) {
|
|
23825
|
-
warnings.push(`${modelPath} is ignored: only a root file named exactly ` + `${INDEX_MODEL_NAME} decides what is published. Fix: rename ` + `it to ${INDEX_MODEL_NAME}.`);
|
|
23826
|
-
}
|
|
23827
|
-
}
|
|
23828
|
-
return { explores: undefined, warnings };
|
|
23829
|
-
}
|
|
23830
|
-
return { explores: [INDEX_MODEL_NAME], warnings };
|
|
23831
|
-
}
|
|
23832
|
-
function listFiles(files) {
|
|
23833
|
-
return files.length <= 1 ? files[0] ?? "" : `${files.slice(0, -1).join(", ")} and ${files[files.length - 1]}`;
|
|
23834
|
-
}
|
|
23835
|
-
function exploresDeprecation(declared, hasIndexModel, reportPaths) {
|
|
23836
|
-
const lead = `"explores" in publisher.json is deprecated.`;
|
|
23837
|
-
const files = declared.filter((entry) => entry !== INDEX_MODEL_NAME && !reportPaths.has(entry));
|
|
23838
|
-
if (files.length > 0) {
|
|
23839
|
-
return hasIndexModel ? `${lead} Fix: import ${listFiles(files)} into ${INDEX_MODEL_NAME}, ` + `export the sources you publish from it, then delete "explores".` : `${lead} Fix: add an ${INDEX_MODEL_NAME} at the package root that ` + `imports ${listFiles(files)} and exports the sources you want to ` + `publish, then delete "explores".`;
|
|
23840
|
-
}
|
|
23841
|
-
if (declared.includes(INDEX_MODEL_NAME)) {
|
|
23842
|
-
return `${lead} ${INDEX_MODEL_NAME} already publishes the same thing. ` + `Fix: delete "explores".`;
|
|
23843
|
-
}
|
|
23844
|
-
return hasIndexModel ? `${lead} Fix: delete "explores", so ${INDEX_MODEL_NAME} decides what is published.` : `${lead} Fix: add an ${INDEX_MODEL_NAME} at the package root that ` + `exports the sources you want to publish, then delete "explores".`;
|
|
23845
|
-
}
|
|
23846
|
-
var EXPLORES_OMITS_INDEX_MODEL = `${INDEX_MODEL_NAME} is ignored because "explores" in publisher.json ` + `doesn't list it. Fix: delete "explores" to publish what ` + `${INDEX_MODEL_NAME} exports, or rename ${INDEX_MODEL_NAME} (and any import ` + `of it) if it isn't meant to decide what is published.`;
|
|
23847
|
-
var EXPLORES_EMPTY_SUPPRESSES_CONVENTION = `"explores" in publisher.json is deprecated. Here it stops ` + `${INDEX_MODEL_NAME} from limiting what this package publishes. Fix: to ` + `publish everything, rename ${INDEX_MODEL_NAME}, point any import of it at ` + `the new name, then delete "explores".`;
|
|
23848
|
-
var EXPLORES_EMPTY_IS_UNCURATED = `"explores": [] in publisher.json does nothing. Fix: delete it.`;
|
|
23849
|
-
var QUERYABLE_SOURCES_DEPRECATION = `"queryableSources" in publisher.json does nothing. Fix: delete it.`;
|
|
23850
|
-
|
|
23851
|
-
// src/package_load/package_load_worker.ts
|
|
23852
|
-
init_package_retrieval();
|
|
23853
|
-
init_source_extraction();
|
|
23854
|
-
init_given();
|
|
23855
|
-
init_utils();
|
|
23856
|
-
|
|
23857
23899
|
// src/package_load/rpc_wait_accountant.ts
|
|
23858
23900
|
class RpcWaitAccountant {
|
|
23859
23901
|
now;
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
// - Publisher.query(model, malloy, opts?) → Promise<rows[]>
|
|
10
10
|
// - Publisher.queryFull(model, malloy, opts?) → Promise<MalloyResult> (envelope for <malloy-render>)
|
|
11
11
|
// opts: { environment?, package?, sourceName?, queryName?, filterParams?,
|
|
12
|
-
// bypassFilters?, givens? }.
|
|
12
|
+
// bypassFilters?, givens?, versionId? }. versionId names a published
|
|
13
|
+
// version; a page opened with `?versionId=` queries its own
|
|
14
|
+
// package at that version by default. givens is a name→value map bound as
|
|
13
15
|
// Malloy given: runtime parameters for this query (safe parameterization,
|
|
14
16
|
// not string interpolation) — see the malloy-html-data-apps skill (reference/runtime.md).
|
|
15
17
|
// - Publisher.embed(selector, { src, height?, token? })
|
|
@@ -68,6 +70,53 @@
|
|
|
68
70
|
return bearerToken ? { Authorization: "Bearer " + bearerToken } : {};
|
|
69
71
|
}
|
|
70
72
|
|
|
73
|
+
// --- Published-version pinning -----------------------------------------
|
|
74
|
+
// A page opened at a published version (`?versionId=` in its URL) queries
|
|
75
|
+
// that version, so it keeps answering from the models it shipped with after
|
|
76
|
+
// the package's `latest` moves on. Only when that version is one the
|
|
77
|
+
// package has: a proxy may forward a page's query string unchanged, with a
|
|
78
|
+
// `versionId` of its own, and such a page queries `latest`, as the server
|
|
79
|
+
// serves its files. One read of the package at the page's version tells.
|
|
80
|
+
function pageVersionParam() {
|
|
81
|
+
// Read by hand, not with URLSearchParams, so the runtime also loads where
|
|
82
|
+
// that is not defined. `+` in a query string is a space.
|
|
83
|
+
var match = (location.search || "").match(/[?&]versionId=([^&#]*)/);
|
|
84
|
+
return match && match[1]
|
|
85
|
+
? safeDecode(match[1].replace(/\+/g, " "))
|
|
86
|
+
: undefined;
|
|
87
|
+
}
|
|
88
|
+
var pageVersion = pageVersionParam();
|
|
89
|
+
var pagePin = null;
|
|
90
|
+
function pinnedVersion() {
|
|
91
|
+
if (!pageVersion || !ctx.environment || !ctx.package) {
|
|
92
|
+
return Promise.resolve(undefined);
|
|
93
|
+
}
|
|
94
|
+
if (!pagePin) {
|
|
95
|
+
pagePin = fetch(
|
|
96
|
+
apiBase +
|
|
97
|
+
"/environments/" +
|
|
98
|
+
encodeURIComponent(ctx.environment) +
|
|
99
|
+
"/packages/" +
|
|
100
|
+
encodeURIComponent(ctx.package) +
|
|
101
|
+
"?versionId=" +
|
|
102
|
+
encodeURIComponent(pageVersion),
|
|
103
|
+
{ credentials: "include", headers: authHeaders() },
|
|
104
|
+
)
|
|
105
|
+
.then(function (res) {
|
|
106
|
+
return res.ok ? res.json() : null;
|
|
107
|
+
})
|
|
108
|
+
.then(function (pkg) {
|
|
109
|
+
return pkg && pkg.versionId === pageVersion
|
|
110
|
+
? pageVersion
|
|
111
|
+
: undefined;
|
|
112
|
+
})
|
|
113
|
+
.catch(function () {
|
|
114
|
+
return undefined;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return pagePin;
|
|
118
|
+
}
|
|
119
|
+
|
|
71
120
|
// --- Query helpers -----------------------------------------------------
|
|
72
121
|
function resolveTarget(opts) {
|
|
73
122
|
var env = (opts && opts.environment) || ctx.environment;
|
|
@@ -106,6 +155,14 @@
|
|
|
106
155
|
if (opts.filterParams) body.filterParams = opts.filterParams;
|
|
107
156
|
if (opts.bypassFilters) body.bypassFilters = true;
|
|
108
157
|
if (opts.givens) body.givens = opts.givens;
|
|
158
|
+
// The page's own version applies only to its own package; a query aimed
|
|
159
|
+
// elsewhere gets that package's latest unless it names one.
|
|
160
|
+
var versionId =
|
|
161
|
+
opts.versionId ||
|
|
162
|
+
(target.env === ctx.environment && target.pkg === ctx.package
|
|
163
|
+
? await pinnedVersion()
|
|
164
|
+
: undefined);
|
|
165
|
+
if (versionId) body.versionId = versionId;
|
|
109
166
|
|
|
110
167
|
var headers = Object.assign(
|
|
111
168
|
{ "content-type": "application/json" },
|