@platforma-open/milaboratories.mixcr-clonotyping-2 2.21.0 → 2.21.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/dist/index.js CHANGED
@@ -21,14 +21,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/plugin_handle.js
24
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/plugin_handle.js
25
25
  const PLUGIN_OUTPUT_PREFIX = "plugin-output#";
26
26
  /** Construct the output key for a plugin output in the block outputs map. */
27
27
  function pluginOutputKey(handle, outputKey) {
28
28
  return `${PLUGIN_OUTPUT_PREFIX}${handle}#${outputKey}`;
29
29
  }
30
30
  //#endregion
31
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/block_storage.js
31
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/block_storage.js
32
32
  /**
33
33
  * Discriminator key for BlockStorage format detection.
34
34
  * This unique hash-based key identifies data as BlockStorage vs legacy formats.
@@ -270,7 +270,7 @@ function getPluginData(rawStorage, handle) {
270
270
  return pluginEntry.__data;
271
271
  }
272
272
  //#endregion
273
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/block_migrations.js
273
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/block_migrations.js
274
274
  /** Create a DataVersioned wrapper with correct shape */
275
275
  function makeVersionedData(version, data) {
276
276
  return {
@@ -765,7 +765,7 @@ var DataModel = class DataModel {
765
765
  }
766
766
  };
767
767
  //#endregion
768
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/internal.js
768
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/internal.js
769
769
  /** Utility code helping to identify whether the code is running in actual UI environment */
770
770
  function isInUI() {
771
771
  return typeof globalThis.getPlatforma !== "undefined" || typeof globalThis.platforma !== "undefined";
@@ -835,7 +835,7 @@ function registerFutureAwait(handle, onResolve) {
835
835
  futureResolves.get(handle).push(onResolve);
836
836
  }
837
837
  //#endregion
838
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/block_storage_facade.js
838
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/block_storage_facade.js
839
839
  /**
840
840
  * All facade callback names as constants.
841
841
  * These are the source of truth - the interface is derived from these.
@@ -870,7 +870,7 @@ function registerFacadeCallbacks(callbacks) {
870
870
  for (const key of Object.values(BlockStorageFacadeCallbacks)) tryRegisterCallback(key, callbacks[key]);
871
871
  }
872
872
  //#endregion
873
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/future.js
873
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/future.js
874
874
  var FutureRef = class FutureRef {
875
875
  handle;
876
876
  postProcess;
@@ -4471,7 +4471,7 @@ objectType({
4471
4471
  to: numberType().min(1)
4472
4472
  });
4473
4473
  //#endregion
4474
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/util.js
4474
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/util.js
4475
4475
  function assertNever(x) {
4476
4476
  throw new Error("Unexpected object: " + x);
4477
4477
  }
@@ -4483,7 +4483,7 @@ function uniqueBy(array, makeId) {
4483
4483
  return [...new Map(array.map((e) => [makeId(e), e])).values()];
4484
4484
  }
4485
4485
  //#endregion
4486
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/data_info.js
4486
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/data_info.js
4487
4487
  /**
4488
4488
  * Type guard function that checks if the given value is a valid DataInfo.
4489
4489
  *
@@ -4674,7 +4674,7 @@ function entriesToDataInfo(dataInfoEntries) {
4674
4674
  }
4675
4675
  }
4676
4676
  //#endregion
4677
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/errors.js
4677
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/errors.js
4678
4678
  var ServiceError = class extends Error {
4679
4679
  name = "ServiceError";
4680
4680
  };
@@ -4698,7 +4698,7 @@ function ensureError(value) {
4698
4698
  return new Error(stringifyValue(value));
4699
4699
  }
4700
4700
  //#endregion
4701
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/json.js
4701
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/json.js
4702
4702
  var import_canonicalize = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
4703
4703
  module.exports = function serialize(object) {
4704
4704
  if (typeof object === "number" && isNaN(object)) throw new Error("NaN is not allowed");
@@ -4731,7 +4731,7 @@ function parseJsonSafely(value, fallback) {
4731
4731
  }
4732
4732
  }
4733
4733
  //#endregion
4734
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/spec.js
4734
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/spec.js
4735
4735
  function readMetadata(metadata, key) {
4736
4736
  return metadata?.[key];
4737
4737
  }
@@ -4982,9 +4982,6 @@ const PColumnName = {
4982
4982
  Sequence: "pl7.app/vdj/sequence"
4983
4983
  }
4984
4984
  };
4985
- function isLabelColumn(column) {
4986
- return column.axesSpec.length === 1 && column.name === PColumnName.Label;
4987
- }
4988
4985
  /** Get column id and spec from a column */
4989
4986
  function getColumnIdAndSpec(column) {
4990
4987
  return {
@@ -5023,7 +5020,7 @@ function matchAxisId(query, target) {
5023
5020
  return query.name === target.name && matchDomain$1(query.domain, target.domain) && matchDomain$1(query.contextDomain, target.contextDomain);
5024
5021
  }
5025
5022
  //#endregion
5026
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/query/utils.js
5023
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/query/utils.js
5027
5024
  const BOOLEAN_TYPES = /* @__PURE__ */ new Set([
5028
5025
  "numericComparison",
5029
5026
  "stringEquals",
@@ -5088,20 +5085,23 @@ function traverseQuerySpec(query, visitor) {
5088
5085
  secondary: query.secondary.map(traverseEntry)
5089
5086
  };
5090
5087
  break;
5091
- case "linkerJoin":
5088
+ case "linkerJoin": {
5089
+ const linker = "type" in query.linker ? query.linker : {
5090
+ type: "column",
5091
+ column: query.linker.column
5092
+ };
5092
5093
  result = {
5093
5094
  ...query,
5094
- linker: {
5095
- ...query.linker,
5096
- column: visitor.column(query.linker.column)
5097
- },
5095
+ linker: traverseQuerySpec(linker, visitor),
5098
5096
  secondary: query.secondary.map(traverseEntry)
5099
5097
  };
5100
5098
  break;
5099
+ }
5101
5100
  case "filter":
5102
5101
  case "sort":
5103
5102
  case "sliceAxes":
5104
5103
  case "transformColumns":
5104
+ case "specOverride":
5105
5105
  result = {
5106
5106
  ...query,
5107
5107
  input: traverseQuerySpec(query.input, visitor)
@@ -5112,19 +5112,28 @@ function traverseQuerySpec(query, visitor) {
5112
5112
  return visitor.node ? visitor.node(result) : result;
5113
5113
  }
5114
5114
  /** Recursively maps all column references in a SpecQuery tree. */
5115
- function mapSpecQueryColumns(query, cb) {
5116
- return traverseQuerySpec(query, { column: cb });
5115
+ function mapSpecQueryColumns(query, visitor) {
5116
+ return traverseQuerySpec(query, visitor);
5117
+ }
5118
+ /** Collects all column references from a SpecQuery tree. */
5119
+ function collectSpecQueryColumns(query) {
5120
+ const result = [];
5121
+ traverseQuerySpec(query, { column: (c) => {
5122
+ result.push(c);
5123
+ return c;
5124
+ } });
5125
+ return result;
5117
5126
  }
5118
5127
  //#endregion
5119
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/table_calculate.js
5128
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/table_calculate.js
5120
5129
  function mapPTableDef(def, cb) {
5121
5130
  return {
5122
5131
  ...def,
5123
5132
  src: mapJoinEntry(def.src, cb)
5124
5133
  };
5125
5134
  }
5126
- function mapPTableDefV2(def, cb) {
5127
- return { query: mapSpecQueryColumns(def.query, cb) };
5135
+ function mapPTableDefV2(def, visitor) {
5136
+ return { query: mapSpecQueryColumns(def.query, visitor) };
5128
5137
  }
5129
5138
  function mapJoinEntry(entry, cb) {
5130
5139
  switch (entry.type) {
@@ -5159,7 +5168,7 @@ function mapJoinEntry(entry, cb) {
5159
5168
  }
5160
5169
  }
5161
5170
  //#endregion
5162
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/table_common.js
5171
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/table_common.js
5163
5172
  function getPTableColumnId(spec) {
5164
5173
  switch (spec.type) {
5165
5174
  case "axis": return {
@@ -5173,17 +5182,366 @@ function getPTableColumnId(spec) {
5173
5182
  }
5174
5183
  }
5175
5184
  //#endregion
5176
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/ids.js
5185
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/filtered_column.js
5186
+ function stringifyColumnFilteredId(key) {
5187
+ return canonicalizeJson(createColumnFilteredKey(key));
5188
+ }
5189
+ function isColumnFilteredKey(obj) {
5190
+ return typeof obj === "object" && obj !== null && "__isFiltered" in obj;
5191
+ }
5192
+ function createColumnFilteredKey(props) {
5193
+ const axisFilters = props.axisFilters.toSorted((a, b) => a[0] - b[0]);
5194
+ return {
5195
+ __isFiltered: true,
5196
+ source: props.source,
5197
+ axisFilters
5198
+ };
5199
+ }
5200
+ /**
5201
+ * Drop the axes pinned by `axisFilters` from a {@link PColumnSpec}'s
5202
+ * `axesSpec`. Indices are positional against `spec.axesSpec`. Returns `spec`
5203
+ * unchanged when there are no filters.
5204
+ *
5205
+ * Single source of the Filtered-layer spec math — shared by
5206
+ * `reconstructSpecFromId` (host, id-walking) and `ColumnFilteredRecipe.getSpec`
5207
+ * (sandbox, recipe-graph walking).
5208
+ */
5209
+ function applyAxisFilters(spec, axisFilters) {
5210
+ if (axisFilters.length === 0) return spec;
5211
+ const fixed = new Set(axisFilters.map(([i]) => i));
5212
+ return {
5213
+ ...spec,
5214
+ axesSpec: spec.axesSpec.filter((_, i) => !fixed.has(i))
5215
+ };
5216
+ }
5217
+ //#endregion
5218
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/pool/spec.js
5219
+ function isPObjectId(value) {
5220
+ if (typeof value !== "string") return false;
5221
+ return isPObjectKey(parseJsonSafely(value));
5222
+ }
5223
+ function isPObjectKey(value) {
5224
+ return isLocalPObjectKey(value) || isGlobalPObjectKey(value);
5225
+ }
5226
+ function createPObjectId(obj) {
5227
+ if (isLocalPObjectKey(obj)) return createLocalPObjectId(obj.resolvePath, obj.name);
5228
+ if (isGlobalPObjectKey(obj)) return createGlobalPObjectId(obj.blockId, obj.name);
5229
+ throw new Error(`createPObjectId: unrecognized object key structure: ${JSON.stringify(obj)}`);
5230
+ }
5231
+ function createLocalPObjectId(resolvePath, name) {
5232
+ return canonicalizeJson({
5233
+ resolvePath,
5234
+ name
5235
+ });
5236
+ }
5237
+ function isLocalPObjectKey(value) {
5238
+ if (typeof value !== "object" || value === null) return false;
5239
+ const v = value;
5240
+ return Array.isArray(v.resolvePath) && typeof v.name === "string";
5241
+ }
5242
+ function createGlobalPObjectId(blockId, exportName) {
5243
+ return canonicalizeJson({
5244
+ __isRef: true,
5245
+ blockId,
5246
+ name: exportName
5247
+ });
5248
+ }
5249
+ function isGlobalPObjectKey(value) {
5250
+ if (typeof value !== "object" || value === null) return false;
5251
+ return "__isRef" in value && "blockId" in value && "name" in value;
5252
+ }
5253
+ function isPObject(obj) {
5254
+ return typeof obj === "object" && obj !== null && "id" in obj && "spec" in obj && "data" in obj;
5255
+ }
5256
+ function isPColumn(obj) {
5257
+ return isPObject(obj) && isPColumnSpec(obj.spec);
5258
+ }
5259
+ function isPColumnSpec(spec) {
5260
+ return spec.kind === "PColumn";
5261
+ }
5262
+ function ensurePColumn(obj) {
5263
+ if (!isPColumn(obj)) throw new Error(`not a PColumn (kind = ${obj.spec.kind})`);
5264
+ return obj;
5265
+ }
5266
+ function mapPObjectData(pObj, cb) {
5267
+ return pObj === void 0 ? void 0 : {
5268
+ ...pObj,
5269
+ data: cb(pObj.data)
5270
+ };
5271
+ }
5272
+ function extractAllColumns(entry) {
5273
+ const columns = /* @__PURE__ */ new Map();
5274
+ const addAllColumns = (entry) => {
5275
+ switch (entry.type) {
5276
+ case "column":
5277
+ columns.set(entry.column.id, entry.column);
5278
+ return;
5279
+ case "slicedColumn":
5280
+ columns.set(entry.column.id, entry.column);
5281
+ return;
5282
+ case "artificialColumn":
5283
+ columns.set(entry.column.id, entry.column);
5284
+ return;
5285
+ case "inlineColumn": return;
5286
+ case "full":
5287
+ case "inner":
5288
+ for (const e of entry.entries) addAllColumns(e);
5289
+ return;
5290
+ case "outer":
5291
+ addAllColumns(entry.primary);
5292
+ for (const e of entry.secondary) addAllColumns(e);
5293
+ return;
5294
+ default: assertNever(entry);
5295
+ }
5296
+ };
5297
+ addAllColumns(entry);
5298
+ return [...columns.values()];
5299
+ }
5300
+ //#endregion
5301
+ //#region ../node_modules/.pnpm/@milaboratories+helpers@1.14.4/node_modules/@milaboratories/helpers/dist/utils.js
5302
+ function isNil$1(v) {
5303
+ return v === null || v === void 0;
5304
+ }
5305
+ Array.isArray;
5306
+ function isObject(value) {
5307
+ return typeof value === "object" && value !== null;
5308
+ }
5309
+ /**
5310
+ * Checks if the given value is a plain object.
5311
+ *
5312
+ * A plain object is defined as an object created by the `{}` literal,
5313
+ * an object created with `Object.create(null)`, or an object with a
5314
+ * prototype that resolves to `Object.prototype`.
5315
+ *
5316
+ * @param value - The value to check.
5317
+ * @returns `true` if the value is a plain object, otherwise `false`.
5318
+ *
5319
+ * @example
5320
+ * ```typescript
5321
+ * isPlainObject({}); // true
5322
+ * isPlainObject(Object.create(null)); // true
5323
+ * isPlainObject(new Date()); // false
5324
+ * isPlainObject(null); // false
5325
+ * isPlainObject([]); // false
5326
+ * ```
5327
+ */
5328
+ function isPlainObject(value) {
5329
+ if (!isObject(value)) return false;
5330
+ const prototype = Object.getPrototypeOf(value);
5331
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
5332
+ }
5333
+ //#endregion
5334
+ //#region ../node_modules/.pnpm/@milaboratories+helpers@1.14.4/node_modules/@milaboratories/helpers/dist/error.js
5335
+ function throwError(v) {
5336
+ if (typeof v === "string") throw new Error(v);
5337
+ else throw v;
5338
+ }
5339
+ //#endregion
5340
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/discovered_column.js
5341
+ function isColumnDiscoveredKey(obj) {
5342
+ return typeof obj === "object" && obj !== null && "__isDiscovered" in obj;
5343
+ }
5344
+ function distillColumnDiscoveredKey(props) {
5345
+ return {
5346
+ __isDiscovered: true,
5347
+ column: props.column,
5348
+ path: Array.isArray(props.path) && props.path.length > 0 ? props.path : void 0,
5349
+ columnQualifications: Array.isArray(props.columnQualifications) && props.columnQualifications.length > 0 ? props.columnQualifications : void 0,
5350
+ queriesQualifications: props.queriesQualifications && Object.keys(props.queriesQualifications).length > 0 ? props.queriesQualifications : void 0
5351
+ };
5352
+ }
5353
+ function stringifyColumnDiscoveredId(id) {
5354
+ return canonicalizeJson(distillColumnDiscoveredKey({
5355
+ __isDiscovered: true,
5356
+ ...id
5357
+ }));
5358
+ }
5359
+ //#endregion
5360
+ //#region ../node_modules/.pnpm/es-toolkit@1.42.0/node_modules/es-toolkit/dist/array/uniq.mjs
5361
+ function uniq(arr) {
5362
+ return [...new Set(arr)];
5363
+ }
5364
+ //#endregion
5365
+ //#region ../node_modules/.pnpm/es-toolkit@1.42.0/node_modules/es-toolkit/dist/array/uniqBy.mjs
5366
+ function uniqBy(arr, mapper) {
5367
+ const map = /* @__PURE__ */ new Map();
5368
+ for (let i = 0; i < arr.length; i++) {
5369
+ const item = arr[i];
5370
+ const key = mapper(item);
5371
+ if (!map.has(key)) map.set(key, item);
5372
+ }
5373
+ return Array.from(map.values());
5374
+ }
5375
+ //#endregion
5376
+ //#region ../node_modules/.pnpm/es-toolkit@1.42.0/node_modules/es-toolkit/dist/predicate/isFunction.mjs
5377
+ function isFunction(value) {
5378
+ return typeof value === "function";
5379
+ }
5380
+ //#endregion
5381
+ //#region ../node_modules/.pnpm/es-toolkit@1.42.0/node_modules/es-toolkit/dist/predicate/isNil.mjs
5382
+ function isNil(x) {
5383
+ return x == null;
5384
+ }
5385
+ //#endregion
5386
+ //#region ../node_modules/.pnpm/es-toolkit@1.42.0/node_modules/es-toolkit/dist/predicate/isString.mjs
5387
+ function isString(value) {
5388
+ return typeof value === "string";
5389
+ }
5390
+ //#endregion
5391
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/ids.js
5177
5392
  /**
5178
- * Canonically serializes a {@link UniversalPColumnId} to a string.
5179
- * @param id - The column identifier to serialize
5180
- * @returns The canonically serialized string
5393
+ * Canonically serializes a column key to a branded string id. Accepts both
5394
+ * the new {@link ColumnUniversalKey} and the deprecated {@link UniversalPColumnId}
5395
+ * (anchored / old filtered object form).
5181
5396
  */
5182
5397
  function stringifyColumnId(id) {
5183
- return (0, import_canonicalize.default)(id);
5398
+ return canonicalizeJson(id);
5399
+ }
5400
+ function parseColumnIdSafely(str, fallback = void 0) {
5401
+ try {
5402
+ return JSON.parse(str);
5403
+ } catch {
5404
+ return fallback;
5405
+ }
5406
+ }
5407
+ /**
5408
+ * Walk a rich column id down to its terminal leaf {@link PObjectId}.
5409
+ */
5410
+ function extractPObjectId(id) {
5411
+ if (isString(id)) {
5412
+ if (isPObjectId(id)) return id;
5413
+ return extractPObjectId(parseColumnIdSafely(id) ?? throwError(`extractPObjectId: id "${id}" is not a valid canonical column id`));
5414
+ }
5415
+ if (isPObjectKey(id)) return createPObjectId(id);
5416
+ if (isColumnFilteredKey(id)) return extractPObjectId(id.source);
5417
+ if (isColumnOverriddenKey(id)) return extractPObjectId(id.source);
5418
+ if (isColumnDiscoveredKey(id)) return extractPObjectId(id.column);
5419
+ throw new Error(`extractPObjectId: unrecognized column id structure: ${JSON.stringify(id)}`);
5420
+ }
5421
+ //#endregion
5422
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/overridden.js
5423
+ function isColumnOverriddenKey(obj) {
5424
+ return typeof obj === "object" && obj !== null && "__isOverridden" in obj;
5425
+ }
5426
+ function distillColumnOverriddenKey(props) {
5427
+ return {
5428
+ __isOverridden: true,
5429
+ source: props.source,
5430
+ specOverrides: props.specOverrides
5431
+ };
5432
+ }
5433
+ function createColumnOverriddenId(props) {
5434
+ return stringifyColumnOverriddenId(createColumnOverriddenKey(props));
5435
+ }
5436
+ function createColumnOverriddenKey(props) {
5437
+ const { source, specOverrides } = props;
5438
+ const unwrapped = unwrapOverrides(source);
5439
+ return {
5440
+ __isOverridden: true,
5441
+ source: unwrapped ? unwrapped.source : source,
5442
+ specOverrides: unwrapped ? mergeSpecOverrides(unwrapped.specOverrides, specOverrides) : specOverrides
5443
+ };
5444
+ }
5445
+ function stringifyColumnOverriddenId(id) {
5446
+ return canonicalizeJson(distillColumnOverriddenKey(id));
5447
+ }
5448
+ /**
5449
+ * Peel one override-wrap layer.
5450
+ *
5451
+ * Invariant: `{source, specOverrides}` can only appear at the top level —
5452
+ * the inner `source` is never itself an override-wrap. Anything else throws.
5453
+ */
5454
+ function unwrapOverrides(id) {
5455
+ const parsed = parseColumnIdSafely(id);
5456
+ if (parsed === void 0 || !isColumnOverriddenKey(parsed)) return void 0;
5457
+ const inner = parseColumnIdSafely(parsed.source);
5458
+ if (inner !== void 0 && isColumnOverriddenKey(inner)) throw new Error("nested override-wrap detected — invariant broken");
5459
+ return parsed;
5460
+ }
5461
+ /**
5462
+ * Apply `specOverrides` from a rich id (`SUniversalPColumnId`) on top of a
5463
+ * resolved {@link PColumnSpec}. Returns `base` unchanged when the id carries
5464
+ * no overrides.
5465
+ */
5466
+ function applySpecOverrides(base, idOrOverride) {
5467
+ if (isNil(idOrOverride)) return base;
5468
+ const overrides = isString(idOrOverride) ? unwrapOverrides(idOrOverride)?.specOverrides : idOrOverride;
5469
+ if (isNil(overrides)) return base;
5470
+ const result = { ...base };
5471
+ if (overrides.annotations) result.annotations = mergeRecord(base.annotations, overrides.annotations);
5472
+ if (overrides.domain) result.domain = mergeRecord(base.domain, overrides.domain);
5473
+ if (overrides.contextDomain) result.contextDomain = mergeRecord(base.contextDomain, overrides.contextDomain);
5474
+ if (overrides.axesSpec) result.axesSpec = applyAxesPatches(base.axesSpec, overrides.axesSpec);
5475
+ return result;
5476
+ }
5477
+ /**
5478
+ * Compose two override patches: applying `mergeSpecOverrides(prior, next)` on
5479
+ * top of a base spec produces the same result as applying `prior` then `next`.
5480
+ */
5481
+ function mergeSpecOverrides(prior, next) {
5482
+ const result = {};
5483
+ const axesSpec = mergeAxesPatches(prior.axesSpec, next.axesSpec);
5484
+ if (axesSpec !== void 0) result.axesSpec = axesSpec;
5485
+ const annotations = mergeRecord(prior.annotations, next.annotations);
5486
+ if (annotations !== void 0) result.annotations = annotations;
5487
+ const domain = mergeRecord(prior.domain, next.domain);
5488
+ if (domain !== void 0) result.domain = domain;
5489
+ const contextDomain = mergeRecord(prior.contextDomain, next.contextDomain);
5490
+ if (contextDomain !== void 0) result.contextDomain = contextDomain;
5491
+ return result;
5492
+ }
5493
+ /**
5494
+ * Apply positional `patches` onto `base.axesSpec`. Patches deep-merge
5495
+ * `annotations` / `domain` / `contextDomain` and shallow-override `name` /
5496
+ * `type` at their slot. Indices `>= base.length` append new axes; intermediate
5497
+ * gaps (if any) are filled with the patch itself, so callers should not leave
5498
+ * holes between base.length and the highest patched index.
5499
+ */
5500
+ function applyAxesPatches(base, patches) {
5501
+ const result = base.slice();
5502
+ for (const [k, p] of Object.entries(patches)) {
5503
+ const i = Number(k);
5504
+ const existing = result[i];
5505
+ result[i] = existing === void 0 ? p : mergeAxisPatch(existing, p);
5506
+ }
5507
+ return result;
5508
+ }
5509
+ /**
5510
+ * Compose two positional patch maps: `mergeAxesPatches(prior, next)` applied to
5511
+ * a base spec must equal applying `prior` then `next`. Patches sharing an
5512
+ * index deep-merge field-by-field.
5513
+ */
5514
+ function mergeAxesPatches(prior, next) {
5515
+ if (!prior || Object.keys(prior).length === 0) return next;
5516
+ if (!next || Object.keys(next).length === 0) return prior;
5517
+ const result = { ...prior };
5518
+ for (const [k, p] of Object.entries(next)) {
5519
+ const i = Number(k);
5520
+ const existing = result[i];
5521
+ result[i] = existing === void 0 ? p : mergeAxisPatch(existing, p);
5522
+ }
5523
+ return result;
5524
+ }
5525
+ function mergeAxisPatch(axis, patch) {
5526
+ const result = {
5527
+ ...axis,
5528
+ ...patch
5529
+ };
5530
+ if (patch.annotations) result.annotations = mergeRecord(axis.annotations, patch.annotations);
5531
+ if (patch.domain) result.domain = mergeRecord(axis.domain, patch.domain);
5532
+ if (patch.contextDomain) result.contextDomain = mergeRecord(axis.contextDomain, patch.contextDomain);
5533
+ return result;
5534
+ }
5535
+ function mergeRecord(a, b) {
5536
+ if (!b) return a;
5537
+ if (!a) return b;
5538
+ return {
5539
+ ...a,
5540
+ ...b
5541
+ };
5184
5542
  }
5185
5543
  //#endregion
5186
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/anchored.js
5544
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/anchored.js
5187
5545
  function axisKey(axis) {
5188
5546
  return (0, import_canonicalize.default)(getAxisId(axis));
5189
5547
  }
@@ -5429,53 +5787,7 @@ function isAnchorAxisRef(value) {
5429
5787
  return typeof value === "object" && "anchor" in value;
5430
5788
  }
5431
5789
  //#endregion
5432
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/pool/spec.js
5433
- function isPColumnSpec(spec) {
5434
- return spec.kind === "PColumn";
5435
- }
5436
- function isPColumn(obj) {
5437
- return isPColumnSpec(obj.spec);
5438
- }
5439
- function ensurePColumn(obj) {
5440
- if (!isPColumn(obj)) throw new Error(`not a PColumn (kind = ${obj.spec.kind})`);
5441
- return obj;
5442
- }
5443
- function mapPObjectData(pObj, cb) {
5444
- return pObj === void 0 ? void 0 : {
5445
- ...pObj,
5446
- data: cb(typeof pObj.data === "function" ? pObj.data() : pObj.data)
5447
- };
5448
- }
5449
- function extractAllColumns(entry) {
5450
- const columns = /* @__PURE__ */ new Map();
5451
- const addAllColumns = (entry) => {
5452
- switch (entry.type) {
5453
- case "column":
5454
- columns.set(entry.column.id, entry.column);
5455
- return;
5456
- case "slicedColumn":
5457
- columns.set(entry.column.id, entry.column);
5458
- return;
5459
- case "artificialColumn":
5460
- columns.set(entry.column.id, entry.column);
5461
- return;
5462
- case "inlineColumn": return;
5463
- case "full":
5464
- case "inner":
5465
- for (const e of entry.entries) addAllColumns(e);
5466
- return;
5467
- case "outer":
5468
- addAllColumns(entry.primary);
5469
- for (const e of entry.secondary) addAllColumns(e);
5470
- return;
5471
- default: assertNever(entry);
5472
- }
5473
- };
5474
- addAllColumns(entry);
5475
- return [...columns.values()];
5476
- }
5477
- //#endregion
5478
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/selectors.js
5790
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/selectors.js
5479
5791
  /**
5480
5792
  * Determines if an axis ID matches an axis selector.
5481
5793
  *
@@ -5556,7 +5868,7 @@ function legacyColumnSelectorsToPredicate(predicateOrSelectors) {
5556
5868
  else return (spec) => isPColumnSpec(spec) && matchPColumn(spec, predicateOrSelectors);
5557
5869
  }
5558
5870
  //#endregion
5559
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/native_id.js
5871
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/spec/native_id.js
5560
5872
  function deriveNativeId(spec) {
5561
5873
  const result = {
5562
5874
  kind: spec.kind,
@@ -5568,19 +5880,7 @@ function deriveNativeId(spec) {
5568
5880
  return (0, import_canonicalize.default)(result);
5569
5881
  }
5570
5882
  //#endregion
5571
- //#region ../node_modules/.pnpm/@milaboratories+helpers@1.14.3/node_modules/@milaboratories/helpers/dist/utils.js
5572
- function isNil$1(v) {
5573
- return v === null || v === void 0;
5574
- }
5575
- Array.isArray;
5576
- //#endregion
5577
- //#region ../node_modules/.pnpm/@milaboratories+helpers@1.14.3/node_modules/@milaboratories/helpers/dist/error.js
5578
- function throwError(v) {
5579
- if (typeof v === "string") throw new Error(v);
5580
- else throw v;
5581
- }
5582
- //#endregion
5583
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/linker_columns.js
5883
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/drivers/pframe/linker_columns.js
5584
5884
  var LinkerMap = class LinkerMap {
5585
5885
  /** Graph of linkers connected by axes (single or grouped by parents) */
5586
5886
  data;
@@ -5758,7 +6058,7 @@ var LinkerMap = class LinkerMap {
5758
6058
  }
5759
6059
  };
5760
6060
  //#endregion
5761
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/flags/block_flags.js
6061
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/flags/block_flags.js
5762
6062
  /**
5763
6063
  * Required PFrames version. Bump this in lockstep with the `@milaboratories/pframes-rs-*`
5764
6064
  * version in `pnpm-workspace.yaml` so blocks built against the new SDK refuse to load on
@@ -5767,7 +6067,7 @@ var LinkerMap = class LinkerMap {
5767
6067
  const REQUIRES_PFRAMES_VERSION = 1001031;
5768
6068
  stringType().length(24).regex(/[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]/).brand("PlId");
5769
6069
  //#endregion
5770
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/ref.js
6070
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/ref.js
5771
6071
  const PlRef = objectType({
5772
6072
  __isRef: literalType(true).describe("Crucial marker for the block dependency tree reconstruction"),
5773
6073
  blockId: stringType().describe("Upstream block id"),
@@ -5803,7 +6103,7 @@ function withEnrichments(ref, requireEnrichments = true) {
5803
6103
  }
5804
6104
  }
5805
6105
  //#endregion
5806
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/value_or_error.js
6106
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/value_or_error.js
5807
6107
  function mapValueInVOE(voe, cb) {
5808
6108
  return voe.ok ? {
5809
6109
  ok: true,
@@ -5811,7 +6111,51 @@ function mapValueInVOE(voe, cb) {
5811
6111
  } : voe;
5812
6112
  }
5813
6113
  //#endregion
5814
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/services/service_types.js
6114
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/resource_types.js
6115
+ /** Well-known resource type names used across the platform. */
6116
+ const ResourceTypeName = {
6117
+ StreamManager: "StreamManager",
6118
+ StdMap: "StdMap",
6119
+ StdMapSlash: "std/map",
6120
+ EphStdMap: "EphStdMap",
6121
+ PFrame: "PFrame",
6122
+ ParquetChunk: "ParquetChunk",
6123
+ BContext: "BContext",
6124
+ BlockPackCustom: "BlockPackCustom",
6125
+ BinaryMap: "BinaryMap",
6126
+ BinaryValue: "BinaryValue",
6127
+ BlobMap: "BlobMap",
6128
+ BResolveSingle: "BResolveSingle",
6129
+ BResolveSingleNoResult: "BResolveSingleNoResult",
6130
+ BQueryResult: "BQueryResult",
6131
+ TengoTemplate: "TengoTemplate",
6132
+ TengoLib: "TengoLib",
6133
+ SoftwareInfo: "SoftwareInfo",
6134
+ Dummy: "Dummy",
6135
+ JsonResourceError: "json/resourceError",
6136
+ JsonObject: "json/object",
6137
+ JsonGzObject: "json-gz/object",
6138
+ JsonString: "json/string",
6139
+ JsonArray: "json/array",
6140
+ JsonNumber: "json/number",
6141
+ BContextEnd: "BContextEnd",
6142
+ FrontendFromUrl: "Frontend/FromUrl",
6143
+ FrontendFromFolder: "Frontend/FromFolder",
6144
+ BObjectSpec: "BObjectSpec",
6145
+ Blob: "Blob",
6146
+ Null: "Null",
6147
+ Binary: "binary",
6148
+ LSProvider: "LSProvider",
6149
+ WorkingDirectory: "WorkingDirectory",
6150
+ UserProject: "UserProject",
6151
+ Projects: "Projects",
6152
+ ClientRoot: "ClientRoot",
6153
+ SharingOutbox: "SharingOutbox",
6154
+ SharingState: "SharingState",
6155
+ SharedEnvelope: "SharedEnvelope"
6156
+ };
6157
+ //#endregion
6158
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/services/service_types.js
5815
6159
  const SERVICE_ID_PATTERN = /^[a-zA-Z][a-zA-Z0-9]*$/;
5816
6160
  const { service, isNodeService, isWasmService, isMainService, getServiceKind, getServiceModelMethods, getServiceUiMethods } = (() => {
5817
6161
  const typeMap = /* @__PURE__ */ new Map();
@@ -5850,7 +6194,7 @@ const { service, isNodeService, isWasmService, isMainService, getServiceKind, ge
5850
6194
  };
5851
6195
  })();
5852
6196
  //#endregion
5853
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/services/service_declarations.js
6197
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/services/service_declarations.js
5854
6198
  const Services = {
5855
6199
  PFrameSpec: service()({
5856
6200
  type: "wasm",
@@ -5908,6 +6252,28 @@ const Services = {
5908
6252
  name: "dialog",
5909
6253
  modelMethods: [],
5910
6254
  uiMethods: ["showSaveDialog"]
6255
+ }),
6256
+ ColumnsCollection: service()({
6257
+ type: "wasm",
6258
+ name: "columnsCollection",
6259
+ modelMethods: [
6260
+ "create",
6261
+ "isEmpty",
6262
+ "isFinal",
6263
+ "getColumns",
6264
+ "addSource",
6265
+ "discover",
6266
+ "filter"
6267
+ ],
6268
+ uiMethods: [
6269
+ "create",
6270
+ "isEmpty",
6271
+ "isFinal",
6272
+ "getColumns",
6273
+ "addSource",
6274
+ "discover",
6275
+ "filter"
6276
+ ]
5911
6277
  })
5912
6278
  };
5913
6279
  Object.keys(Services).map((key) => `requires${key}`);
@@ -5922,7 +6288,7 @@ function resolveRequiredServices(flags) {
5922
6288
  }
5923
6289
  Object.fromEntries(Object.keys(Services).map((key) => [`requires${key}`, true]));
5924
6290
  //#endregion
5925
- //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.46.4/node_modules/@milaboratories/pl-model-common/dist/services/service_injectors.js
6291
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/services/service_injectors.js
5926
6292
  function buildMethodMap(pick) {
5927
6293
  const result = {};
5928
6294
  for (const id of Object.values(Services)) result[id] = [...pick(id)];
@@ -5931,26 +6297,269 @@ function buildMethodMap(pick) {
5931
6297
  buildMethodMap(getServiceUiMethods);
5932
6298
  buildMethodMap(getServiceModelMethods);
5933
6299
  //#endregion
5934
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/accessor.js
5935
- function ifDef(value, cb) {
5936
- return value === void 0 ? void 0 : cb(value);
6300
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/columns/accessor_traversal.js
6301
+ /** Resource types that hold column collections — DFS stops here and collects. */
6302
+ const COLLECT_TYPES = [ResourceTypeName.PFrame];
6303
+ /** Resource types DFS descends through when looking for PFrames. */
6304
+ const DESCEND_TYPES = [ResourceTypeName.StdMap, ResourceTypeName.StdMapSlash];
6305
+ /**
6306
+ * Enumerate column names backing a PFrame accessor — derived from
6307
+ * `<name>.spec` field names, without resolving the spec resources.
6308
+ */
6309
+ function listColumnNames(accessor, prefix = "") {
6310
+ if (accessor.resourceType.name !== ResourceTypeName.PFrame) return [];
6311
+ const out = [];
6312
+ for (const field of accessor.listInputFields()) {
6313
+ if (!field.endsWith(".spec")) continue;
6314
+ const raw = field.slice(0, -5);
6315
+ if (!raw.startsWith(prefix)) continue;
6316
+ out.push(raw.slice(prefix.length));
6317
+ }
6318
+ return out;
5937
6319
  }
5938
6320
  /**
5939
- * Decode an error node's content into a display message. The backend serializes
5940
- * a resource error as `{"message": "..."}` (`ResourceError`); unwrap that to the
5941
- * human-readable message. Falls back to the raw string when the content is not
5942
- * that envelope (e.g. plain text, or an unexpected shape).
6321
+ * DFS over the input-field subtree of `root`. Collects nodes whose resource
6322
+ * type ∈ `collectTypes`. Descends only through `descendTypes`
6323
+ * (default: StdMap / StdMapSlash). Collected nodes are not descended into.
6324
+ *
6325
+ * Threads the field-name path from `rootPath` to each hit, so callers can
6326
+ * build canonical {@link createLocalPObjectId}s without relying on the
6327
+ * accessor itself to remember its path.
6328
+ *
6329
+ * Includes `root` itself in the walk.
5943
6330
  */
5944
- function decodeErrorMessage(raw) {
5945
- try {
5946
- const parsed = JSON.parse(raw);
5947
- if (typeof parsed?.message === "string") return parsed.message;
5948
- } catch {}
5949
- return raw;
6331
+ function findDescendantsByType(opts) {
6332
+ const { root, rootPath, collectTypes, descendTypes = DESCEND_TYPES } = opts;
6333
+ const collectSet = new Set(collectTypes);
6334
+ const descendSet = new Set(descendTypes);
6335
+ const result = [];
6336
+ const stack = [{
6337
+ node: root,
6338
+ path: rootPath
6339
+ }];
6340
+ while (stack.length > 0) {
6341
+ const { node, path } = stack.pop();
6342
+ const typeName = node.resourceType.name;
6343
+ if (collectSet.has(typeName)) {
6344
+ result.push({
6345
+ node,
6346
+ path
6347
+ });
6348
+ continue;
6349
+ }
6350
+ if (!descendSet.has(typeName)) continue;
6351
+ const fields = node.listInputFields();
6352
+ for (let i = fields.length - 1; i >= 0; i--) {
6353
+ const child = node.traverse({
6354
+ field: fields[i],
6355
+ assertFieldType: "Input",
6356
+ ignoreError: true
6357
+ });
6358
+ if (child !== void 0) stack.push({
6359
+ node: child,
6360
+ path: [...path, fields[i]]
6361
+ });
6362
+ }
6363
+ }
6364
+ return result;
5950
6365
  }
5951
- /** Represent resource tree node accessor */
5952
- var TreeNodeAccessor = class TreeNodeAccessor {
5953
- handle;
6366
+ /**
6367
+ * Walk an accessor root and return one {@link LeafEntry} per discovered column.
6368
+ * Ids are {@link createLocalPObjectId}-shaped: `{resolvePath, name}`. The
6369
+ * `resolvePath` is derived from `rootPath` extended by the DFS traversal.
6370
+ */
6371
+ function indexAccessorRoot(root, rootPath) {
6372
+ const result = [];
6373
+ for (const { node, path } of findDescendantsByType({
6374
+ root,
6375
+ rootPath,
6376
+ collectTypes: COLLECT_TYPES,
6377
+ descendTypes: DESCEND_TYPES
6378
+ })) for (const name of listColumnNames(node)) result.push({
6379
+ accessor: node,
6380
+ name,
6381
+ id: createLocalPObjectId([...path], name)
6382
+ });
6383
+ return result;
6384
+ }
6385
+ /**
6386
+ * Walk one upstream-block ctx pair (`prodCtx` then `stagingCtx`) and return one
6387
+ * {@link LeafEntry} per column. First-wins dedup by name (prod precedes staging).
6388
+ * Ids are {@link createGlobalPObjectId}-shaped — `resolvePath` is not involved.
6389
+ */
6390
+ function indexPoolBlock(block) {
6391
+ const accessors = [];
6392
+ if (block.prodCtx) accessors.push(block.prodCtx);
6393
+ if (block.stagingCtx) accessors.push(block.stagingCtx);
6394
+ const result = [];
6395
+ const seen = /* @__PURE__ */ new Set();
6396
+ for (const accessor of accessors) for (const name of listColumnNames(accessor)) {
6397
+ if (seen.has(name)) continue;
6398
+ seen.add(name);
6399
+ result.push({
6400
+ accessor,
6401
+ name,
6402
+ id: createGlobalPObjectId(block.blockId, name)
6403
+ });
6404
+ }
6405
+ return result;
6406
+ }
6407
+ //#endregion
6408
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/columns/column_registry.js
6409
+ /**
6410
+ * Id-index over a set of {@link ColumnEntriesProvider}s. Sole job:
6411
+ * {@link PObjectId} → {@link LeafEntry}. Generic over the accessor flavour, so
6412
+ * the same class backs both sandbox (`TreeNodeAccessor`) and host
6413
+ * (`PlTreeNodeAccessor`) usage.
6414
+ *
6415
+ * Stateless beyond the provider list — every lookup goes through each
6416
+ * provider's `getPObjectEntries()` (cached inside the provider). Instantiate
6417
+ * directly at the call site that has the providers; there is no ambient
6418
+ * singleton.
6419
+ */
6420
+ var ColumnRegistry = class {
6421
+ providers;
6422
+ constructor(providers) {
6423
+ this.providers = providers;
6424
+ }
6425
+ /**
6426
+ * Resolve a {@link PObjectId} to its backing {@link LeafEntry}. Returns
6427
+ * `undefined` if the column is not reachable from any provider — caller
6428
+ * decides whether that's `absent` or `resolving` via {@link isFinal}.
6429
+ */
6430
+ resolve(id) {
6431
+ return this.lookupById(id);
6432
+ }
6433
+ /** Whether every indexed source has finished enumerating its columns. */
6434
+ isFinal() {
6435
+ return this.providers.every((p) => p.isFinal());
6436
+ }
6437
+ lookupById(id) {
6438
+ for (const p of this.providers) {
6439
+ const hit = p.getPObjectEntries().get(id);
6440
+ if (hit !== void 0) return hit;
6441
+ }
6442
+ }
6443
+ };
6444
+ //#endregion
6445
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/columns/dedup.js
6446
+ /**
6447
+ * Two-track dedup over an item stream keyed by `ColumnUniversalId`:
6448
+ *
6449
+ * - **Raw `PObjectId`s** are deduped by `deriveNativeId(spec)`. The same
6450
+ * physical column reached via outputs vs. result_pool has different
6451
+ * id shapes but identical nativeId — first occurrence wins so the
6452
+ * provider order (outputs before pool) decides which id is canonical.
6453
+ * - **Non-`PObjectId` ids** (e.g. `SUniversalPColumnUniversalId`,
6454
+ * `ColumnDiscoveredId`) keep raw-id dedup — they legitimately share
6455
+ * nativeId with siblings.
6456
+ *
6457
+ * When `getSpec` returns `undefined` for a `PObjectId`, falls back to raw-id
6458
+ * dedup (so an unresolvable id still survives instead of dropping silently).
6459
+ *
6460
+ * Shared by sandbox-side `extractColumns` (column_providers) and host-side
6461
+ * `ColumnsCollectionDriverImpl.getColumns` — both layers need identical
6462
+ * dedup semantics, but operate on different concrete item types (ColumnLazy
6463
+ * vs. raw ColumnUniversalId).
6464
+ */
6465
+ function dedupColumns(items, getId, getSpec) {
6466
+ const seenNative = /* @__PURE__ */ new Set();
6467
+ const seenId = /* @__PURE__ */ new Set();
6468
+ const out = [];
6469
+ for (const item of items) {
6470
+ const id = getId(item);
6471
+ if (seenId.has(id)) continue;
6472
+ if (isPObjectId(id)) {
6473
+ const spec = getSpec(item);
6474
+ if (spec !== void 0) {
6475
+ const nativeId = deriveNativeId(spec);
6476
+ if (seenNative.has(nativeId)) continue;
6477
+ seenNative.add(nativeId);
6478
+ }
6479
+ }
6480
+ seenId.add(id);
6481
+ out.push(item);
6482
+ }
6483
+ return out;
6484
+ }
6485
+ //#endregion
6486
+ //#region ../node_modules/.pnpm/@milaboratories+pl-model-common@1.47.1/node_modules/@milaboratories/pl-model-common/dist/columns/providers.js
6487
+ /**
6488
+ * Generic entries provider over a single accessor root. Walks `<root>` once
6489
+ * from the supplied `rootPath`, builds an id → {@link LeafEntry} map and
6490
+ * exposes `isFinal()` via the root's `getInputsLocked()`.
6491
+ *
6492
+ * Used directly on the host side; sandbox extends it with `getColumns()`
6493
+ * returning {@link ColumnLazy}s — see `AccessorColumnsProvider` in
6494
+ * `@platforma-sdk/model`.
6495
+ */
6496
+ var AccessorEntriesProvider = class {
6497
+ root;
6498
+ entries;
6499
+ constructor(root, rootPath) {
6500
+ this.root = root;
6501
+ const map = /* @__PURE__ */ new Map();
6502
+ for (const entry of indexAccessorRoot(root, rootPath)) if (!map.has(entry.id)) map.set(entry.id, entry);
6503
+ this.entries = map;
6504
+ }
6505
+ getPObjectEntries() {
6506
+ return this.entries;
6507
+ }
6508
+ isFinal() {
6509
+ return this.root.getInputsLocked();
6510
+ }
6511
+ };
6512
+ /**
6513
+ * Generic entries provider over a list of upstream-block ctx pairs.
6514
+ *
6515
+ * Per-block merge: iterate `prod` then `staging`, dedupe by name with
6516
+ * first-wins semantics (prod takes precedence).
6517
+ *
6518
+ * `isFinal()` is the AND of `getInputsLocked()` over every present ctx
6519
+ * accessor and `!prodIncomplete && !stagingIncomplete` over every block.
6520
+ */
6521
+ var ResultPoolEntriesProvider = class {
6522
+ blocks;
6523
+ cachedEntries;
6524
+ constructor(blocks) {
6525
+ this.blocks = blocks;
6526
+ }
6527
+ getPObjectEntries() {
6528
+ if (this.cachedEntries !== void 0) return this.cachedEntries;
6529
+ const map = /* @__PURE__ */ new Map();
6530
+ for (const block of this.blocks) for (const entry of indexPoolBlock(block)) if (!map.has(entry.id)) map.set(entry.id, entry);
6531
+ return this.cachedEntries = map;
6532
+ }
6533
+ isFinal() {
6534
+ for (const block of this.blocks) {
6535
+ if (block.prodIncomplete || block.stagingIncomplete) return false;
6536
+ if (block.prodCtx && !block.prodCtx.getInputsLocked()) return false;
6537
+ if (block.stagingCtx && !block.stagingCtx.getInputsLocked()) return false;
6538
+ }
6539
+ return true;
6540
+ }
6541
+ };
6542
+ //#endregion
6543
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/accessor.js
6544
+ function ifDef(value, cb) {
6545
+ return value === void 0 ? void 0 : cb(value);
6546
+ }
6547
+ /**
6548
+ * Decode an error node's content into a display message. The backend serializes
6549
+ * a resource error as `{"message": "..."}` (`ResourceError`); unwrap that to the
6550
+ * human-readable message. Falls back to the raw string when the content is not
6551
+ * that envelope (e.g. plain text, or an unexpected shape).
6552
+ */
6553
+ function decodeErrorMessage(raw) {
6554
+ try {
6555
+ const parsed = JSON.parse(raw);
6556
+ if (typeof parsed?.message === "string") return parsed.message;
6557
+ } catch {}
6558
+ return raw;
6559
+ }
6560
+ /** Represent resource tree node accessor */
6561
+ var TreeNodeAccessor = class TreeNodeAccessor {
6562
+ handle;
5954
6563
  resolvePath;
5955
6564
  constructor(handle, resolvePath) {
5956
6565
  this.handle = handle;
@@ -5977,7 +6586,7 @@ var TreeNodeAccessor = class TreeNodeAccessor {
5977
6586
  }));
5978
6587
  return this.resolveWithCommon({}, ...transformedSteps);
5979
6588
  }
5980
- resolveAny(...steps) {
6589
+ traverse(...steps) {
5981
6590
  return this.resolveWithCommon({}, ...steps);
5982
6591
  }
5983
6592
  resolveWithCommon(commonOptions, ...steps) {
@@ -6023,6 +6632,9 @@ var TreeNodeAccessor = class TreeNodeAccessor {
6023
6632
  if (content == void 0) throw new Error("Resource has no content.");
6024
6633
  return JSON.parse(content);
6025
6634
  }
6635
+ hasData() {
6636
+ return getCfgRenderCtx().hasData(this.handle);
6637
+ }
6026
6638
  getDataBase64() {
6027
6639
  return getCfgRenderCtx().getDataBase64(this.handle);
6028
6640
  }
@@ -6059,9 +6671,16 @@ var TreeNodeAccessor = class TreeNodeAccessor {
6059
6671
  }
6060
6672
  return this.getDataAsJson();
6061
6673
  }
6062
- /**
6063
- *
6064
- */
6674
+ getFileContentAsBase64(range) {
6675
+ return new FutureRef(getCfgRenderCtx().getBlobContentAsBase64(this.handle, range));
6676
+ }
6677
+ getFileContentAsString(range) {
6678
+ return new FutureRef(getCfgRenderCtx().getBlobContentAsString(this.handle, range));
6679
+ }
6680
+ getFileContentAsJson(range) {
6681
+ return new FutureRef(getCfgRenderCtx().getBlobContentAsString(this.handle, range)).mapDefined((v) => JSON.parse(v));
6682
+ }
6683
+ /** @deprecated */
6065
6684
  getPColumns(errorOnUnknownField = false, prefix = "") {
6066
6685
  const result = this.parsePObjectCollection(errorOnUnknownField, prefix);
6067
6686
  if (result === void 0) return void 0;
@@ -6070,9 +6689,7 @@ var TreeNodeAccessor = class TreeNodeAccessor {
6070
6689
  return obj;
6071
6690
  });
6072
6691
  }
6073
- /**
6074
- *
6075
- */
6692
+ /** @deprecated */
6076
6693
  parsePObjectCollection(errorOnUnknownField = false, prefix = "") {
6077
6694
  const pObjects = getCfgRenderCtx().parsePObjectCollection(this.handle, errorOnUnknownField, prefix, ...this.resolvePath);
6078
6695
  if (pObjects === void 0) return void 0;
@@ -6083,15 +6700,6 @@ var TreeNodeAccessor = class TreeNodeAccessor {
6083
6700
  }
6084
6701
  return result;
6085
6702
  }
6086
- getFileContentAsBase64(range) {
6087
- return new FutureRef(getCfgRenderCtx().getBlobContentAsBase64(this.handle, range));
6088
- }
6089
- getFileContentAsString(range) {
6090
- return new FutureRef(getCfgRenderCtx().getBlobContentAsString(this.handle, range));
6091
- }
6092
- getFileContentAsJson(range) {
6093
- return new FutureRef(getCfgRenderCtx().getBlobContentAsString(this.handle, range)).mapDefined((v) => JSON.parse(v));
6094
- }
6095
6703
  /**
6096
6704
  * @deprecated use getFileContentAsBase64
6097
6705
  */
@@ -6182,11 +6790,11 @@ var TreeNodeAccessor = class TreeNodeAccessor {
6182
6790
  }
6183
6791
  };
6184
6792
  //#endregion
6185
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/internal.js
6186
- const StagingAccessorName = "staging";
6793
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/internal.js
6187
6794
  const MainAccessorName = "main";
6795
+ const StagingAccessorName = "staging";
6188
6796
  //#endregion
6189
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/util/axis_filtering.js
6797
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/util/axis_filtering.js
6190
6798
  function filterDataInfoEntries(dataInfoEntries, axisFilters) {
6191
6799
  const sortedFilters = [...axisFilters].sort((a, b) => b[0] - a[0]);
6192
6800
  const { type } = dataInfoEntries;
@@ -6250,22 +6858,7 @@ function filterDataInfoEntries(dataInfoEntries, axisFilters) {
6250
6858
  }
6251
6859
  }
6252
6860
  //#endregion
6253
- //#region ../node_modules/.pnpm/es-toolkit@1.42.0/node_modules/es-toolkit/dist/function/identity.mjs
6254
- function identity(x) {
6255
- return x;
6256
- }
6257
- //#endregion
6258
- //#region ../node_modules/.pnpm/es-toolkit@1.42.0/node_modules/es-toolkit/dist/predicate/isFunction.mjs
6259
- function isFunction(value) {
6260
- return typeof value === "function";
6261
- }
6262
- //#endregion
6263
- //#region ../node_modules/.pnpm/es-toolkit@1.42.0/node_modules/es-toolkit/dist/predicate/isNil.mjs
6264
- function isNil(x) {
6265
- return x == null;
6266
- }
6267
- //#endregion
6268
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/labels/derive_distinct_labels.js
6861
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/labels/derive_distinct_labels.js
6269
6862
  const DISTANCE_PENALTY = .001;
6270
6863
  const LABEL_TYPE = "__LABEL__";
6271
6864
  const LABEL_TYPE_FULL = "__LABEL__@1";
@@ -6531,7 +7124,7 @@ function minimizeTypeSet(typeSet, records, stats, forceTraceElements, forcedSet,
6531
7124
  return result;
6532
7125
  }
6533
7126
  //#endregion
6534
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/util/label.js
7127
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/util/label.js
6535
7128
  /** @deprecated Use deriveDistinctLabels */
6536
7129
  function deriveLabels(values, getSpec, options = {}) {
6537
7130
  return deriveDistinctLabels(values.map(getSpec), options).map((label, i) => ({
@@ -6540,7 +7133,7 @@ function deriveLabels(values, getSpec, options = {}) {
6540
7133
  }));
6541
7134
  }
6542
7135
  //#endregion
6543
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/util/pcolumn_data.js
7136
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/util/pcolumn_data.js
6544
7137
  const RT_RESOURCE_MAP = "PColumnData/ResourceMap";
6545
7138
  const RT_RESOURCE_MAP_PARTITIONED = "PColumnData/Partitioned/ResourceMap";
6546
7139
  const RT_JSON_PARTITIONED = "PColumnData/JsonPartitioned";
@@ -6872,7 +7465,7 @@ function isPColumnReady(c) {
6872
7465
  const isValues = (d) => Array.isArray(d);
6873
7466
  const isAccessor = (d) => d instanceof TreeNodeAccessor;
6874
7467
  let ready = true;
6875
- const data = typeof c.data === "function" ? c.data() : c.data;
7468
+ const data = c.data;
6876
7469
  if (data == null) return false;
6877
7470
  else if (isAccessor(data)) ready &&= data.getIsReadyOrError();
6878
7471
  else if (isDataInfo(data)) visitDataInfo(data, (v) => ready &&= v.getIsReadyOrError());
@@ -6883,7 +7476,7 @@ function allPColumnsReady(columns) {
6883
7476
  return columns.every(isPColumnReady);
6884
7477
  }
6885
7478
  //#endregion
6886
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/util/column_collection.js
7479
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/util/column_collection.js
6887
7480
  function isPColumnValues(value) {
6888
7481
  if (!Array.isArray(value)) return false;
6889
7482
  if (value.length === 0) return true;
@@ -6893,7 +7486,7 @@ function isPColumnValues(value) {
6893
7486
  /**
6894
7487
  * A simple implementation of {@link ColumnProvider} backed by a pre-defined array of columns.
6895
7488
  */
6896
- var ArrayColumnProvider = class {
7489
+ var ArrayColumnsProvider = class {
6897
7490
  columns;
6898
7491
  constructor(columns) {
6899
7492
  this.columns = columns;
@@ -6945,7 +7538,7 @@ function getSplitAxisIndices(selector) {
6945
7538
  }
6946
7539
  var PColumnCollection = class {
6947
7540
  defaultProviderStore = [];
6948
- providers = [new ArrayColumnProvider(this.defaultProviderStore)];
7541
+ providers = [new ArrayColumnsProvider(this.defaultProviderStore)];
6949
7542
  axisLabelProviders = [];
6950
7543
  constructor() {}
6951
7544
  addColumnProvider(provider) {
@@ -7108,7 +7701,9 @@ var PColumnCollection = class {
7108
7701
  result.push({
7109
7702
  id: finalId,
7110
7703
  spec: finalSpec,
7111
- data: () => entry.type === "split" ? entriesToDataInfo(filterDataInfoEntries(entry.dataEntries, axisFiltersTuple)) : entry.originalColumn.data,
7704
+ get data() {
7705
+ return entry.type === "split" ? entriesToDataInfo(filterDataInfoEntries(entry.dataEntries, axisFiltersTuple)) : entry.originalColumn.data;
7706
+ },
7112
7707
  label
7113
7708
  });
7114
7709
  }
@@ -7144,7 +7739,7 @@ var PColumnCollection = class {
7144
7739
  if (!entries) return void 0;
7145
7740
  const columns = [];
7146
7741
  for (const entry of entries) {
7147
- const data = entry.data();
7742
+ const data = entry.data;
7148
7743
  if (!data) {
7149
7744
  if (opts?.dontWaitAllData) continue;
7150
7745
  return;
@@ -7159,7 +7754,7 @@ var PColumnCollection = class {
7159
7754
  }
7160
7755
  };
7161
7756
  //#endregion
7162
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/services/block_services.js
7757
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/services/block_services.js
7163
7758
  /**
7164
7759
  * Services required by all V3 blocks by default.
7165
7760
  * Edit this when a new service should be available to all blocks.
@@ -7170,11 +7765,12 @@ var PColumnCollection = class {
7170
7765
  const BLOCK_SERVICE_FLAGS = {
7171
7766
  requiresPFrameSpec: true,
7172
7767
  requiresPFrame: true,
7173
- requiresDialog: true
7768
+ requiresDialog: true,
7769
+ requiresColumnsCollection: true
7174
7770
  };
7175
7771
  resolveRequiredServices(BLOCK_SERVICE_FLAGS);
7176
7772
  //#endregion
7177
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/services/service_bridge.js
7773
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/services/service_bridge.js
7178
7774
  /**
7179
7775
  * Builds a ServiceProxy from a ServiceDispatch.
7180
7776
  * Each service method call is forwarded to dispatch.callServiceMethod.
@@ -7183,10 +7779,10 @@ function createServiceProxy(dispatch) {
7183
7779
  return ((serviceId) => Object.freeze(Object.fromEntries(dispatch.getServiceMethods(serviceId).map((method) => [method, (...args) => dispatch.callServiceMethod(serviceId, method, ...args)]))));
7184
7780
  }
7185
7781
  //#endregion
7186
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/services/get_services.js
7782
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/services/get_services.js
7187
7783
  const cachedServices = /* @__PURE__ */ new WeakMap();
7188
- function getService(name) {
7189
- const ctx = getCfgRenderCtx();
7784
+ function getService(name, deps) {
7785
+ const ctx = deps?.ctx ?? getCfgRenderCtx();
7190
7786
  const map = cachedServices.has(ctx) ? cachedServices.get(ctx) : (() => {
7191
7787
  cachedServices.set(ctx, /* @__PURE__ */ new Map());
7192
7788
  return cachedServices.get(ctx);
@@ -7197,7 +7793,7 @@ function getService(name) {
7197
7793
  })();
7198
7794
  }
7199
7795
  //#endregion
7200
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/util/pframe_upgraders.js
7796
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/util/pframe_upgraders.js
7201
7797
  function patchInSetFilters(filters) {
7202
7798
  const inSetToOrEqual = (predicate) => {
7203
7799
  if (predicate.operator !== "InSet") return predicate;
@@ -7235,7 +7831,7 @@ function patchInSetFilters(filters) {
7235
7831
  return filters.map((filter) => mapFilter(filter, inSetToOrEqual));
7236
7832
  }
7237
7833
  //#endregion
7238
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/render/api.js
7834
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/render/api.js
7239
7835
  /**
7240
7836
  * Helper function to match domain objects
7241
7837
  * @param query Optional domain to match against
@@ -7250,24 +7846,35 @@ function matchDomain(query, target) {
7250
7846
  }
7251
7847
  /**
7252
7848
  * Transforms PColumn data into the internal representation expected by the platform
7253
- * @param data Data from a PColumn to transform
7849
+ * @param column Data from a PColumn to transform
7254
7850
  * @returns Transformed data compatible with platform API
7255
7851
  */
7256
- function transformPColumnData(data) {
7257
- return mapPObjectData(data, (d) => {
7258
- if (d instanceof TreeNodeAccessor) return d.handle;
7259
- else if (isDataInfo(d)) return mapDataInfo(d, (accessor) => accessor.handle);
7260
- else return d ?? [];
7852
+ function finalizePColumnData(column) {
7853
+ return mapPObjectData(column, (data) => {
7854
+ if (data instanceof TreeNodeAccessor) return data.handle;
7855
+ else if (isDataInfo(data)) {
7856
+ let ready = true;
7857
+ visitDataInfo(data, (accessor) => ready &&= accessor?.getIsReadyOrError() ?? false);
7858
+ if (!ready) return [];
7859
+ return mapDataInfo(data, (accessor) => accessor?.handle ?? throwError("Accessor handle is undefined"));
7860
+ } else return data ?? [];
7261
7861
  });
7262
7862
  }
7863
+ /**
7864
+ * @deprecated use the direct `ctx.*` methods on `RenderCtxBase` instead.
7865
+ *
7866
+ * Migration map:
7867
+ * - `getSpecs` → `ctx.getSpecs`
7868
+ * - `getSpecByRef` / `getPColumnSpecByRef` → `ctx.getSpecByRef` / `ctx.getPColumnSpecByRef`
7869
+ * - `getDataByRef` / `getPColumnByRef` → `ctx.getDataByRef` / `ctx.getPColumnByRef`
7870
+ * - `getOptions` → `ctx.getOptions`
7871
+ *
7872
+ * Eager methods `selectColumns` / `getData` / `getDataWithErrors` should be
7873
+ * replaced by `ctx.getSpecs` + on-demand `ctx.getStatusByRef` /
7874
+ * `ctx.getPColumnByRef` so that the data resource is not subscribed up-front.
7875
+ */
7263
7876
  var ResultPool = class {
7264
7877
  ctx = getCfgRenderCtx();
7265
- /**
7266
- * @deprecated use getOptions()
7267
- */
7268
- calculateOptions(predicate) {
7269
- return this.ctx.calculateOptions(predicate);
7270
- }
7271
7878
  getOptions(predicateOrSelector, opts) {
7272
7879
  const predicate = typeof predicateOrSelector === "function" ? predicateOrSelector : legacyColumnSelectorsToPredicate(predicateOrSelector);
7273
7880
  const filtered = this.getSpecs().entries.filter((s) => predicate(s.obj));
@@ -7411,7 +8018,6 @@ var ResultPool = class {
7411
8018
  * @returns data associated with the ref
7412
8019
  */
7413
8020
  getDataByRef(ref) {
7414
- if (typeof this.ctx.getDataFromResultPoolByRef === "undefined") return this.getData().entries.find((f) => f.ref.blockId === ref.blockId && f.ref.name === ref.name)?.obj;
7415
8021
  const data = this.ctx.getDataFromResultPoolByRef(ref.blockId, ref.name);
7416
8022
  if (!data) return void 0;
7417
8023
  return mapPObjectData(data, (handle) => new TreeNodeAccessor(handle, [ref.blockId, ref.name]));
@@ -7492,6 +8098,9 @@ var ResultPool = class {
7492
8098
  *
7493
8099
  * @param selectors - A predicate function, a single selector, or an array of selectors.
7494
8100
  * @returns An array of PColumn objects matching the selectors. Data is loaded on first access.
8101
+ * @deprecated use `RenderCtxBase.rawResultPool` + `ResultPoolColumnsProvider` +
8102
+ * `discoverColumns` instead. This eager path materializes column data
8103
+ * unnecessarily for callers that only filter by spec.
7495
8104
  */
7496
8105
  selectColumns(selectors) {
7497
8106
  const predicate = typeof selectors === "function" ? selectors : legacyColumnSelectorsToPredicate(selectors);
@@ -7569,20 +8178,8 @@ var RenderCtxBase = class {
7569
8178
  get outputs() {
7570
8179
  return this.getNamedAccessor(MainAccessorName);
7571
8180
  }
8181
+ /** @deprecated use `rawResultPool` + `ResultPoolColumnsProvider` instead. */
7572
8182
  resultPool = new ResultPool();
7573
- /**
7574
- * Find labels data for a given axis id. It will search for a label column and return its data as a map.
7575
- * @returns a map of axis value => label
7576
- * @deprecated Use resultPool.findLabels instead
7577
- */
7578
- findLabels(axis) {
7579
- return this.resultPool.findLabels(axis);
7580
- }
7581
- verifyInlineAndExplicitColumnsSupport(columns) {
7582
- const hasInlineColumns = columns.some((c) => !(c.data instanceof TreeNodeAccessor) || isDataInfo(c.data));
7583
- const inlineColumnsSupport = this.ctx.featureFlags?.inlineColumnsSupport === true;
7584
- if (hasInlineColumns && !inlineColumnsSupport) throw Error(`Inline or explicit columns not supported`);
7585
- }
7586
8183
  patchPTableDef(def) {
7587
8184
  if (!this.ctx.featureFlags?.pTablePartitionFiltersSupport) def = {
7588
8185
  ...def,
@@ -7597,7 +8194,7 @@ var RenderCtxBase = class {
7597
8194
  return def;
7598
8195
  }
7599
8196
  createPFrame(def) {
7600
- return this.ctx.createPFrame(def.map((c) => transformPColumnData(c)));
8197
+ return this.ctx.createPFrame(def.map((v) => isString(v) ? v : finalizePColumnData(v)));
7601
8198
  }
7602
8199
  createPTable(def) {
7603
8200
  let rawDef;
@@ -7614,17 +8211,11 @@ var RenderCtxBase = class {
7614
8211
  sorting: def.sorting ?? []
7615
8212
  });
7616
8213
  else rawDef = this.patchPTableDef(def);
7617
- const columns = extractAllColumns(rawDef.src);
7618
- this.verifyInlineAndExplicitColumnsSupport(columns);
7619
- if (!allPColumnsReady(columns)) return void 0;
7620
- return this.ctx.createPTable(mapPTableDef(rawDef, (po) => transformPColumnData(po)));
8214
+ if (!allPColumnsReady(extractAllColumns(rawDef.src))) return void 0;
8215
+ return this.ctx.createPTable(mapPTableDef(rawDef, finalizePColumnData));
7621
8216
  }
7622
8217
  createPTableV2(def) {
7623
- return this.ctx.createPTableV2(mapPTableDefV2(def, (po) => transformPColumnData(po)));
7624
- }
7625
- /** @deprecated scheduled for removal from SDK */
7626
- getBlockLabel(blockId) {
7627
- return this.ctx.getBlockLabel(blockId);
8218
+ return this.ctx.createPTableV2(mapPTableDefV2(def, { column: (v) => isString(v) ? v : finalizePColumnData(v) }));
7628
8219
  }
7629
8220
  getCurrentUnstableMarker() {
7630
8221
  return this.ctx.getCurrentUnstableMarker();
@@ -7689,27 +8280,27 @@ var PluginRenderCtx = class extends RenderCtxBase {
7689
8280
  }
7690
8281
  };
7691
8282
  //#endregion
7692
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/version.js
7693
- const PlatformaSDKVersion = "1.79.27";
8283
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/version.js
8284
+ const PlatformaSDKVersion = "1.80.2";
7694
8285
  //#endregion
7695
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/bconfig/types.js
8286
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/bconfig/types.js
7696
8287
  function isConfigLambda(cfgOrFh) {
7697
8288
  return cfgOrFh.__renderLambda === true;
7698
8289
  }
7699
8290
  //#endregion
7700
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/bconfig/normalization.js
8291
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/bconfig/normalization.js
7701
8292
  function downgradeCfgOrLambda(data) {
7702
8293
  if (data === void 0) return void 0;
7703
8294
  if (isConfigLambda(data)) return data.handle;
7704
8295
  return data;
7705
8296
  }
7706
8297
  //#endregion
7707
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/plugin_model.js
8298
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/plugin_model.js
7708
8299
  /** Internal plugin↔block handshake. `Symbol.for` (not `Symbol`) so it stays
7709
8300
  * identical across multiple `@platforma-sdk/model` copies in one process. */
7710
8301
  const CREATE_PLUGIN_MODEL = Symbol.for("@platforma-sdk/model:createPluginModel");
7711
8302
  //#endregion
7712
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/block_storage_callbacks.js
8303
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/block_storage_callbacks.js
7713
8304
  /**
7714
8305
  * BlockStorage Callback Implementations - wired to facade callbacks in BlockModelV3.done().
7715
8306
  *
@@ -7886,7 +8477,7 @@ function derivePrerunArgsFromStorage(storageJson, argsFunction, prerunArgsFuncti
7886
8477
  }
7887
8478
  }
7888
8479
  //#endregion
7889
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/block_model.js
8480
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/block_model.js
7890
8481
  /**
7891
8482
  * Merges two feature flag objects with type-aware logic:
7892
8483
  * - `supports*` (boolean): OR — `true` if either side is `true`
@@ -8143,62 +8734,2320 @@ var BlockModelV3 = class BlockModelV3 {
8143
8734
  [BlockStorageFacadeCallbacks.ArgsDerive]: (storageJson) => deriveArgsFromStorage(storageJson, argsFunction),
8144
8735
  [BlockStorageFacadeCallbacks.PrerunArgsDerive]: (storageJson) => derivePrerunArgsFromStorage(storageJson, argsFunction, prerunArgsFunction)
8145
8736
  });
8146
- const pluginOutputs = {};
8147
- for (const handle of pluginHandles) {
8148
- const { model, inputs } = plugins[handle];
8149
- const wrappedInputs = {};
8150
- for (const [paramKey, paramFn] of Object.entries(inputs)) wrappedInputs[paramKey] = () => paramFn(new BlockRenderCtx());
8151
- const outputs = model.outputs;
8152
- for (const [outputKey, outputFn] of Object.entries(outputs)) {
8153
- const key = pluginOutputKey(handle, outputKey);
8154
- pluginOutputs[key] = createAndRegisterRenderLambda({
8155
- handle: key,
8156
- lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs)),
8157
- withStatus: true
8158
- });
8159
- }
8737
+ const pluginOutputs = {};
8738
+ for (const handle of pluginHandles) {
8739
+ const { model, inputs } = plugins[handle];
8740
+ const wrappedInputs = {};
8741
+ for (const [paramKey, paramFn] of Object.entries(inputs)) wrappedInputs[paramKey] = () => paramFn(new BlockRenderCtx());
8742
+ const outputs = model.outputs;
8743
+ for (const [outputKey, outputFn] of Object.entries(outputs)) {
8744
+ const key = pluginOutputKey(handle, outputKey);
8745
+ pluginOutputs[key] = createAndRegisterRenderLambda({
8746
+ handle: key,
8747
+ lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs)),
8748
+ withStatus: true
8749
+ });
8750
+ }
8751
+ }
8752
+ const allOutputs = {
8753
+ ...this.config.outputs,
8754
+ ...pluginOutputs
8755
+ };
8756
+ globalThis.platformaApiVersion = apiVersion;
8757
+ if (!isInUI()) return { config: {
8758
+ v4: {
8759
+ configVersion: 4,
8760
+ modelAPIVersion: 2,
8761
+ sdkVersion: PlatformaSDKVersion,
8762
+ renderingMode: this.config.renderingMode,
8763
+ sections: this.config.sections,
8764
+ title: this.config.title,
8765
+ subtitle: this.config.subtitle,
8766
+ tags: this.config.tags,
8767
+ outputs: allOutputs,
8768
+ enrichmentTargets: this.config.enrichmentTargets,
8769
+ featureFlags: this.config.featureFlags,
8770
+ blockLifecycleCallbacks: { ...BlockStorageFacadeHandles }
8771
+ },
8772
+ sdkVersion: PlatformaSDKVersion,
8773
+ renderingMode: this.config.renderingMode,
8774
+ sections: this.config.sections,
8775
+ outputs: Object.fromEntries(Object.entries(this.config.outputs).map(([key, value]) => [key, downgradeCfgOrLambda(value)]))
8776
+ } };
8777
+ else return {
8778
+ ...getPlatformaInstance({
8779
+ sdkVersion: PlatformaSDKVersion,
8780
+ apiVersion
8781
+ }),
8782
+ blockModelInfo: {
8783
+ outputs: Object.fromEntries(Object.entries(allOutputs).map(([key, value]) => [key, { withStatus: Boolean(isConfigLambda(value) && value.withStatus) }])),
8784
+ pluginIds: pluginHandles,
8785
+ featureFlags: this.config.featureFlags,
8786
+ pluginPublicOutputs: Object.fromEntries(pluginHandles.map((handle) => [handle, plugins[handle].model.publicOutputDef]))
8787
+ }
8788
+ };
8789
+ }
8790
+ };
8791
+ //#endregion
8792
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column_recipes/leaf_rebrand.js
8793
+ /**
8794
+ * Replace every column leaf whose id equals `fromId` with `toId`, leaving
8795
+ * other column refs (linkers, sub-anchors) intact. Wrapper recipes
8796
+ * (Overridden / Filtered) and Discovered use this to lift their own id onto
8797
+ * the hit leaf, so per-variant uniqueness propagates to the engine and
8798
+ * resolver-emitted ids match leaves in the emitted SpecQuery.
8799
+ *
8800
+ * Generic over all SpecQuery node shapes — including `linkerJoin`, which
8801
+ * occurs when a wrapper sits over a {@link ColumnDiscoveredRecipe}: only
8802
+ * the deepest hit leaf carries `fromId`, every linker leaf has a different
8803
+ * id and is left untouched.
8804
+ */
8805
+ function rebrandLeafId(node, fromId, toId) {
8806
+ if (fromId === toId) return node;
8807
+ return mapSpecQueryColumns(node, { column: (id) => id === fromId ? toId : id });
8808
+ }
8809
+ //#endregion
8810
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column_recipes/column_overrided_recipe.js
8811
+ /**
8812
+ * Recipe wrapper that overlays {@link SpecOverrides} on top of any other
8813
+ * recipe. The id is `ColumnOverriddenKey { source: inner.id, specOverrides }`.
8814
+ *
8815
+ * Flat-merge invariant: `inner` is never another {@link ColumnOverriddenRecipe}.
8816
+ * Repeated overrides go through {@link wrap} / {@link withSpecs}, which merge
8817
+ * `specOverrides` at the current level and keep wrapper depth constant.
8818
+ *
8819
+ * This invariant matches the one enforced inside `unwrapOverrides` from
8820
+ * pl-model-common: it explicitly throws on a nested override-wrap.
8821
+ */
8822
+ var ColumnOverriddenRecipe = class ColumnOverriddenRecipe {
8823
+ inner;
8824
+ overrides;
8825
+ /**
8826
+ * Wrap any recipe with overrides. If `inner` is already a
8827
+ * {@link ColumnOverriddenRecipe}, merges `overrides` into the existing ones
8828
+ * and returns a new Overridden sharing the original `inner`. No
8829
+ * `Overridden<Overridden<X>>` is produced.
8830
+ */
8831
+ static wrap(col, overrides) {
8832
+ if (col instanceof ColumnOverriddenRecipe) return new ColumnOverriddenRecipe(col.inner, mergeSpecOverrides(col.overrides, overrides));
8833
+ return new ColumnOverriddenRecipe(col, overrides);
8834
+ }
8835
+ /**
8836
+ * Static counterpart to {@link wrap}: returns the resolution status of a
8837
+ * {@link ColumnOverriddenKey} without constructing the recipe. Overrides
8838
+ * do not add references — status collapses to the source's status.
8839
+ */
8840
+ static getStatusByKey(key, opts = {}) {
8841
+ return ColumnRecipe.getStatus(key.source, opts);
8842
+ }
8843
+ id;
8844
+ specCache;
8845
+ queryCache;
8846
+ dataStatusCache;
8847
+ constructor(inner, overrides) {
8848
+ this.inner = inner;
8849
+ this.overrides = overrides;
8850
+ this.id = createColumnOverriddenId({
8851
+ source: inner.id,
8852
+ specOverrides: overrides
8853
+ });
8854
+ }
8855
+ /** Wrapped recipe — exposed so external walkers can descend. */
8856
+ getInner() {
8857
+ return this.inner;
8858
+ }
8859
+ /**
8860
+ * `inner` owns all references; overrides are a pure spec patch and do not
8861
+ * introduce new column refs.
8862
+ */
8863
+ getReferencedIds() {
8864
+ return this.inner.getReferencedIds();
8865
+ }
8866
+ getDataStatus() {
8867
+ if (this.dataStatusCache === void 0) this.dataStatusCache = { value: this.inner.getDataStatus() };
8868
+ return this.dataStatusCache.value;
8869
+ }
8870
+ /**
8871
+ * Take the inner spec and overlay our overrides. `applySpecOverrides`
8872
+ * extracts the overrides from `this.id` itself.
8873
+ */
8874
+ getSpec() {
8875
+ if (this.specCache === void 0) this.specCache = { value: applySpecOverrides(this.inner.getSpec(), this.id) };
8876
+ return this.specCache.value;
8877
+ }
8878
+ /**
8879
+ * Emit a client-side `specOverride` node wrapping the inner query.
8880
+ *
8881
+ * This is a structural-but-collapsible node: it carries the override
8882
+ * patch through the query tree so consumers see the full recipe shape,
8883
+ * but it is collapsed at the host boundary (`resolvePColumn`) before
8884
+ * the query reaches pframe-engine. The engine never sees this node.
8885
+ *
8886
+ * Overrides do not change query topology — they are a pure spec patch.
8887
+ */
8888
+ getQuery() {
8889
+ if (this.queryCache === void 0) this.queryCache = { value: {
8890
+ type: "specOverride",
8891
+ input: rebrandLeafId(this.inner.getQuery(), this.inner.id, this.id),
8892
+ override: this.overrides
8893
+ } };
8894
+ return this.queryCache.value;
8895
+ }
8896
+ /**
8897
+ * Flat merge: new overrides merge with existing ones; `inner` is unchanged.
8898
+ * The result is an Overridden of the same depth.
8899
+ */
8900
+ withSpecs(overrides) {
8901
+ return ColumnOverriddenRecipe.wrap(this, overrides);
8902
+ }
8903
+ };
8904
+ //#endregion
8905
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column_recipes/column_discovered_recipe.js
8906
+ /**
8907
+ * Recipe for columns identified by a {@link ColumnDiscoveredKey}: a base
8908
+ * column + a `path` of linkers + qualifications.
8909
+ *
8910
+ * Specifics:
8911
+ * - References more than one column (`column` + each `path[i].column`);
8912
+ * {@link getDataStatus} aggregates across the whole set.
8913
+ * - {@link getQuery} assembles the {@link SpecQuery} locally
8914
+ * ({@link buildSpecQuery}) — the hit is inlined as its own recipe's query
8915
+ * tree, linkers fold inside-out into nested `linkerJoin` nodes.
8916
+ * - {@link getSpec} passes through to the hit column's own spec: the linker
8917
+ * chain only enables co-indexing and does not remap the hit's `axesSpec`, so
8918
+ * no engine round-trip is needed (mirrors the Discovered branch of
8919
+ * `reconstructSpecFromId` on the host side).
8920
+ */
8921
+ var ColumnDiscoveredRecipe = class ColumnDiscoveredRecipe {
8922
+ key;
8923
+ columns;
8924
+ /**
8925
+ * Validate the key + resolve every referenced column via
8926
+ * {@link ColumnLazy.fromId} (which itself checks the leaf accessor reports
8927
+ * `hasData()`). Returns `undefined` if the key is malformed or any
8928
+ * referenced column is not yet spec-resolvable.
8929
+ *
8930
+ * Spec JSON is deserialized lazily on first {@link getSpec}/{@link getQuery}.
8931
+ */
8932
+ static fromKey(key, opts = {}) {
8933
+ const distilled = distillColumnDiscoveredKey(key);
8934
+ const columns = {};
8935
+ for (const uniId of referencedUniIdsOf(distilled)) {
8936
+ const recipe = Column(uniId, opts);
8937
+ if (recipe === void 0) return void 0;
8938
+ columns[uniId] = recipe;
8939
+ }
8940
+ return new ColumnDiscoveredRecipe(distilled, columns);
8941
+ }
8942
+ /**
8943
+ * Static counterpart to {@link fromKey}: returns the resolution status of
8944
+ * a {@link ColumnDiscoveredKey} without constructing the recipe. Worst-wins
8945
+ * across every referenced {@link ColumnUniversalId} (hit + path linkers),
8946
+ * each resolved via the top-level {@link ColumnRecipe.getStatus} dispatcher.
8947
+ */
8948
+ static getStatusByKey(key, opts = {}) {
8949
+ const distilled = distillColumnDiscoveredKey(key);
8950
+ let worst = "present";
8951
+ for (const uniId of referencedUniIdsOf(distilled)) {
8952
+ const s = ColumnRecipe.getStatus(uniId, opts);
8953
+ if (s === "absent") return "absent";
8954
+ if (s === "resolving") worst = "resolving";
8955
+ }
8956
+ return worst;
8957
+ }
8958
+ id;
8959
+ specCache;
8960
+ queryCache;
8961
+ dataStatusCache;
8962
+ constructor(key, columns) {
8963
+ this.key = key;
8964
+ this.columns = columns;
8965
+ this.id = stringifyColumnDiscoveredId(this.key);
8966
+ }
8967
+ /**
8968
+ * Universal id of the hit column (excluding path/qualifications on top).
8969
+ * May itself be a wrapped id (Overridden / Filtered / nested Discovered) —
8970
+ * preserves projections applied to the underlying column.
8971
+ */
8972
+ getHitId() {
8973
+ return this.key.column;
8974
+ }
8975
+ /**
8976
+ * Axis qualifications attached to the hit column itself — applied to the
8977
+ * outer-join entry that wraps this column at the consumer boundary.
8978
+ */
8979
+ getColumnQualifications() {
8980
+ return this.key.columnQualifications ?? [];
8981
+ }
8982
+ /**
8983
+ * Per-primary-column qualifications applied to the primary anchors on
8984
+ * this group's side. Keyed by the external primary column id.
8985
+ */
8986
+ getQueriesQualifications() {
8987
+ return this.key.queriesQualifications ?? {};
8988
+ }
8989
+ /**
8990
+ * Leaf {@link PObjectId}s the recipe physically depends on: hit column +
8991
+ * each linker in `path`, with any projection wrappers unwrapped down to
8992
+ * their underlying storage column. Used to track real-data dependencies
8993
+ * (e.g. {@link getDataStatus}), not projected identities.
8994
+ */
8995
+ getReferencedIds() {
8996
+ return [...new Set([...referencedUniIdsOf(this.key)].map((uniId) => extractPObjectId(uniId)))];
8997
+ }
8998
+ /**
8999
+ * Final spec of a discovered hit is just the hit column's own spec: the
9000
+ * linker chain only enables co-indexing, it does not remap the hit's
9001
+ * `axesSpec`, and axis qualifications live on the outer join entry (see
9002
+ * {@link buildSpecQuery}), not in the spec. So pass through to the hit
9003
+ * recipe's `getSpec()` — no engine round-trip needed. This mirrors the
9004
+ * Discovered branch of `reconstructSpecFromId` on the host side.
9005
+ */
9006
+ getSpec() {
9007
+ if (this.specCache === void 0) {
9008
+ const hit = this.columns[this.key.column] ?? throwError(`ColumnDiscoveredRecipe.getSpec: missing column ${this.key.column}`);
9009
+ this.specCache = { value: hit.getSpec() };
9010
+ }
9011
+ return this.specCache.value;
9012
+ }
9013
+ /** IR for building the final spec — see {@link buildSpecQuery}. */
9014
+ getQuery() {
9015
+ if (this.queryCache === void 0) this.queryCache = { value: this.buildSpecQuery() };
9016
+ return this.queryCache.value;
9017
+ }
9018
+ getDataStatus() {
9019
+ if (this.dataStatusCache === void 0) this.dataStatusCache = { value: Object.values(this.columns).reduce((worst, lazy) => {
9020
+ const s = lazy.getDataStatus();
9021
+ if (s === "absent" || worst === "absent") return "absent";
9022
+ if (s === "resolving") return "resolving";
9023
+ return worst;
9024
+ }, "present") };
9025
+ return this.dataStatusCache.value;
9026
+ }
9027
+ /**
9028
+ * Discovered + overrides → Overridden<Discovered>. Delegates to the
9029
+ * flat-merge factory of ColumnOverriddenRecipe; subsequent `withSpecs`
9030
+ * calls merge at the Overridden level (one wrapper, no nesting).
9031
+ */
9032
+ withSpecs(overrides) {
9033
+ return ColumnOverriddenRecipe.wrap(this, overrides);
9034
+ }
9035
+ /**
9036
+ * Assembles the SpecQuery for this discovered hit by folding `key.path`
9037
+ * around the hit column.
9038
+ *
9039
+ * The hit (innermost) is built by inlining `columns[key.column].getQuery()`
9040
+ * — recursing into the hit's own recipe — so wrapping layers on the hit
9041
+ * (Overridden / Filtered / nested Discovered) appear in the produced tree.
9042
+ * The previous `pframeSpec.buildQuery` path was a flat
9043
+ * {@link PObjectId}-only call and could not express that.
9044
+ *
9045
+ * Linkers stay as plain column references on the linker side of
9046
+ * `linkerJoin` (the spec node has no slot for a query-side linker); the
9047
+ * linker's recipe id is used directly. The frame registered in
9048
+ * {@link getSpec} carries each recipe's final spec under that same id, so
9049
+ * the engine resolves linker axes from the post-projection spec.
9050
+ *
9051
+ * Path ordering matches {@link ColumnDiscoveredKey.path}: `path[0]` is
9052
+ * outermost, `path[N-1]` is closest to the hit. We fold from the inside
9053
+ * out — innermost wrap first — so the result lines up with that convention.
9054
+ *
9055
+ * `columnQualifications` / `queriesQualifications` are not emitted here —
9056
+ * qualifications live on a {@link SpecQueryJoinEntry} wrapper (lost on
9057
+ * unwrapping to {@link SpecQuery}). External consumers apply them at the
9058
+ * outer join via {@link getColumnQualifications} / {@link getQueriesQualifications}.
9059
+ */
9060
+ buildSpecQuery() {
9061
+ const hitRecipe = this.columns[this.key.column] ?? throwError(`ColumnDiscoveredRecipe.buildSpecQuery: missing column ${this.key.column}`);
9062
+ let query = rebrandLeafId(hitRecipe.getQuery(), hitRecipe.id, this.id);
9063
+ const path = this.key.path ?? [];
9064
+ for (let i = path.length - 1; i >= 0; i--) query = {
9065
+ type: "linkerJoin",
9066
+ linker: (this.columns[path[i].column] ?? throwError(`ColumnDiscoveredRecipe.buildSpecQuery: missing linker column ${path[i].column}`)).getQuery(),
9067
+ secondary: [{ entry: query }]
9068
+ };
9069
+ return query;
9070
+ }
9071
+ };
9072
+ function referencedUniIdsOf(key) {
9073
+ return /* @__PURE__ */ new Set([key.column, ...(key.path ?? []).map((item) => item.column)]);
9074
+ }
9075
+ //#endregion
9076
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column_recipes/column_filtered_recipe.js
9077
+ /**
9078
+ * Recipe wrapper that fixes the values of selected axes of an inner recipe
9079
+ * (axis slicing). The id is `FilteredPColumnId { source: inner.id,
9080
+ * axisFilters }`.
9081
+ *
9082
+ * Flat-merge invariant: `inner` is never another {@link ColumnFilteredRecipe}.
9083
+ * Repeated {@link wrap} concatenates `axisFilters` at the current level.
9084
+ *
9085
+ * Layering: `withSpecs` on a Filtered recipe yields
9086
+ * `Overridden<Filtered<inner>>` — Overridden is always the outermost layer.
9087
+ * The reverse layering (`Filtered<Overridden<...>>`) is not reachable via
9088
+ * the public interface.
9089
+ */
9090
+ var ColumnFilteredRecipe = class ColumnFilteredRecipe {
9091
+ inner;
9092
+ axisFilters;
9093
+ /**
9094
+ * Wrap any recipe with axis filters. If `inner` is already a
9095
+ * {@link ColumnFilteredRecipe}, concatenates `axisFilters` and returns a
9096
+ * new Filtered sharing the original `inner`.
9097
+ *
9098
+ * Validates every axis index against `inner.getSpec().axesSpec` at
9099
+ * construction — throws on an out-of-range index. After {@link wrap}, the
9100
+ * recipe is guaranteed to be spec-complete.
9101
+ *
9102
+ * Order semantics: new filters are appended after existing ones, preserving
9103
+ * their relative order. AND composition is otherwise commutative; order
9104
+ * only affects canonicalize/equality.
9105
+ */
9106
+ static wrap(col, axisFilters) {
9107
+ const combined = col instanceof ColumnFilteredRecipe ? [...col.axisFilters, ...axisFilters] : axisFilters;
9108
+ const base = col instanceof ColumnFilteredRecipe ? col.inner : col;
9109
+ if (combined.length === 0) throw new Error("ColumnFilteredRecipe.wrap: at least one axis filter must be provided");
9110
+ const innerSpec = base.getSpec();
9111
+ const fixed = /* @__PURE__ */ new Set();
9112
+ for (const [idx] of combined) {
9113
+ if (innerSpec.axesSpec[idx] === void 0) throw new Error(`ColumnFilteredRecipe.wrap: axis index ${idx} out of range (inner has ${innerSpec.axesSpec.length} axes)`);
9114
+ fixed.add(idx);
9115
+ }
9116
+ if (fixed.size >= innerSpec.axesSpec.length) throw new Error(`ColumnFilteredRecipe.wrap: filters fix all ${innerSpec.axesSpec.length} axes — at least one axis must remain`);
9117
+ return new ColumnFilteredRecipe(base, combined);
9118
+ }
9119
+ /**
9120
+ * Static counterpart to {@link wrap}: returns the resolution status of a
9121
+ * {@link ColumnFilteredKey} without constructing the recipe. Axis filters
9122
+ * do not add references — status collapses to the source's status.
9123
+ */
9124
+ static getStatusByKey(key, opts = {}) {
9125
+ if (typeof key.source !== "string") throw new Error("ColumnFilteredRecipe.getStatusByKey: filtered column with non-string source");
9126
+ return ColumnRecipe.getStatus(key.source, opts);
9127
+ }
9128
+ id;
9129
+ specCache;
9130
+ queryCache;
9131
+ dataStatusCache;
9132
+ constructor(inner, axisFilters) {
9133
+ this.inner = inner;
9134
+ this.axisFilters = axisFilters;
9135
+ this.id = stringifyColumnFilteredId({
9136
+ source: inner.id,
9137
+ axisFilters
9138
+ });
9139
+ }
9140
+ /** Wrapped recipe — exposed so external walkers can descend. */
9141
+ getInner() {
9142
+ return this.inner;
9143
+ }
9144
+ /** Axis filters do not introduce references to other columns. */
9145
+ getReferencedIds() {
9146
+ return this.inner.getReferencedIds();
9147
+ }
9148
+ getDataStatus() {
9149
+ if (this.dataStatusCache === void 0) this.dataStatusCache = { value: this.inner.getDataStatus() };
9150
+ return this.dataStatusCache.value;
9151
+ }
9152
+ /**
9153
+ * Final spec — the inner spec with fixed axes removed. Indices in
9154
+ * `axisFilters` are positional against `inner.getSpec().axesSpec` and were
9155
+ * validated at {@link wrap} time.
9156
+ */
9157
+ getSpec() {
9158
+ if (this.specCache === void 0) this.specCache = { value: applyAxisFilters(this.inner.getSpec(), this.axisFilters) };
9159
+ return this.specCache.value;
9160
+ }
9161
+ /**
9162
+ * Wraps the inner query in `SpecQuerySliceAxes`. Index→selector resolution
9163
+ * goes through the inner spec — guaranteed available since {@link wrap}
9164
+ * validated all indices at construction.
9165
+ */
9166
+ getQuery() {
9167
+ if (this.queryCache === void 0) {
9168
+ const innerQuery = this.inner.getQuery();
9169
+ if (this.axisFilters.length === 0) this.queryCache = { value: rebrandLeafId(innerQuery, this.inner.id, this.id) };
9170
+ else {
9171
+ const innerSpec = this.inner.getSpec();
9172
+ this.queryCache = { value: {
9173
+ type: "sliceAxes",
9174
+ input: rebrandLeafId(innerQuery, this.inner.id, this.id),
9175
+ axisFilters: this.axisFilters.map(([idx, value]) => ({
9176
+ axisSelector: toAxisSelector(innerSpec.axesSpec[idx]),
9177
+ constant: value
9178
+ }))
9179
+ } };
9180
+ }
9181
+ }
9182
+ return this.queryCache.value;
9183
+ }
9184
+ /**
9185
+ * Filtered + overrides → Overridden<Filtered>. Overridden is always the
9186
+ * outermost layer.
9187
+ */
9188
+ withSpecs(overrides) {
9189
+ return ColumnOverriddenRecipe.wrap(this, overrides);
9190
+ }
9191
+ };
9192
+ function toAxisSelector(axis) {
9193
+ const selector = {
9194
+ name: axis.name,
9195
+ type: axis.type
9196
+ };
9197
+ if (axis.domain !== void 0 && Object.keys(axis.domain).length > 0) selector.domain = axis.domain;
9198
+ if (axis.contextDomain !== void 0 && Object.keys(axis.contextDomain).length > 0) selector.contextDomain = axis.contextDomain;
9199
+ return selector;
9200
+ }
9201
+ //#endregion
9202
+ //#region ../node_modules/.pnpm/lru-cache@11.2.4/node_modules/lru-cache/dist/esm/index.js
9203
+ /**
9204
+ * @module LRUCache
9205
+ */
9206
+ const defaultPerf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
9207
+ const warned = /* @__PURE__ */ new Set();
9208
+ /* c8 ignore start */
9209
+ const PROCESS = typeof process === "object" && !!process ? process : {};
9210
+ /* c8 ignore start */
9211
+ const emitWarning = (msg, type, code, fn) => {
9212
+ typeof PROCESS.emitWarning === "function" ? PROCESS.emitWarning(msg, type, code, fn) : console.error(`[${code}] ${type}: ${msg}`);
9213
+ };
9214
+ let AC = globalThis.AbortController;
9215
+ let AS = globalThis.AbortSignal;
9216
+ /* c8 ignore start */
9217
+ if (typeof AC === "undefined") {
9218
+ AS = class AbortSignal {
9219
+ onabort;
9220
+ _onabort = [];
9221
+ reason;
9222
+ aborted = false;
9223
+ addEventListener(_, fn) {
9224
+ this._onabort.push(fn);
9225
+ }
9226
+ };
9227
+ AC = class AbortController {
9228
+ constructor() {
9229
+ warnACPolyfill();
9230
+ }
9231
+ signal = new AS();
9232
+ abort(reason) {
9233
+ if (this.signal.aborted) return;
9234
+ this.signal.reason = reason;
9235
+ this.signal.aborted = true;
9236
+ for (const fn of this.signal._onabort) fn(reason);
9237
+ this.signal.onabort?.(reason);
9238
+ }
9239
+ };
9240
+ let printACPolyfillWarning = PROCESS.env?.LRU_CACHE_IGNORE_AC_WARNING !== "1";
9241
+ const warnACPolyfill = () => {
9242
+ if (!printACPolyfillWarning) return;
9243
+ printACPolyfillWarning = false;
9244
+ emitWarning("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.", "NO_ABORT_CONTROLLER", "ENOTSUP", warnACPolyfill);
9245
+ };
9246
+ }
9247
+ /* c8 ignore stop */
9248
+ const shouldWarn = (code) => !warned.has(code);
9249
+ const isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
9250
+ /* c8 ignore start */
9251
+ const getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null;
9252
+ /* c8 ignore stop */
9253
+ var ZeroArray = class extends Array {
9254
+ constructor(size) {
9255
+ super(size);
9256
+ this.fill(0);
9257
+ }
9258
+ };
9259
+ var Stack = class Stack {
9260
+ heap;
9261
+ length;
9262
+ static #constructing = false;
9263
+ static create(max) {
9264
+ const HeapCls = getUintArray(max);
9265
+ if (!HeapCls) return [];
9266
+ Stack.#constructing = true;
9267
+ const s = new Stack(max, HeapCls);
9268
+ Stack.#constructing = false;
9269
+ return s;
9270
+ }
9271
+ constructor(max, HeapCls) {
9272
+ /* c8 ignore start */
9273
+ if (!Stack.#constructing) throw new TypeError("instantiate Stack using Stack.create(n)");
9274
+ /* c8 ignore stop */
9275
+ this.heap = new HeapCls(max);
9276
+ this.length = 0;
9277
+ }
9278
+ push(n) {
9279
+ this.heap[this.length++] = n;
9280
+ }
9281
+ pop() {
9282
+ return this.heap[--this.length];
9283
+ }
9284
+ };
9285
+ /**
9286
+ * Default export, the thing you're using this module to get.
9287
+ *
9288
+ * The `K` and `V` types define the key and value types, respectively. The
9289
+ * optional `FC` type defines the type of the `context` object passed to
9290
+ * `cache.fetch()` and `cache.memo()`.
9291
+ *
9292
+ * Keys and values **must not** be `null` or `undefined`.
9293
+ *
9294
+ * All properties from the options object (with the exception of `max`,
9295
+ * `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
9296
+ * added as normal public members. (The listed options are read-only getters.)
9297
+ *
9298
+ * Changing any of these will alter the defaults for subsequent method calls.
9299
+ */
9300
+ var LRUCache = class LRUCache {
9301
+ #max;
9302
+ #maxSize;
9303
+ #dispose;
9304
+ #onInsert;
9305
+ #disposeAfter;
9306
+ #fetchMethod;
9307
+ #memoMethod;
9308
+ #perf;
9309
+ /**
9310
+ * {@link LRUCache.OptionsBase.perf}
9311
+ */
9312
+ get perf() {
9313
+ return this.#perf;
9314
+ }
9315
+ /**
9316
+ * {@link LRUCache.OptionsBase.ttl}
9317
+ */
9318
+ ttl;
9319
+ /**
9320
+ * {@link LRUCache.OptionsBase.ttlResolution}
9321
+ */
9322
+ ttlResolution;
9323
+ /**
9324
+ * {@link LRUCache.OptionsBase.ttlAutopurge}
9325
+ */
9326
+ ttlAutopurge;
9327
+ /**
9328
+ * {@link LRUCache.OptionsBase.updateAgeOnGet}
9329
+ */
9330
+ updateAgeOnGet;
9331
+ /**
9332
+ * {@link LRUCache.OptionsBase.updateAgeOnHas}
9333
+ */
9334
+ updateAgeOnHas;
9335
+ /**
9336
+ * {@link LRUCache.OptionsBase.allowStale}
9337
+ */
9338
+ allowStale;
9339
+ /**
9340
+ * {@link LRUCache.OptionsBase.noDisposeOnSet}
9341
+ */
9342
+ noDisposeOnSet;
9343
+ /**
9344
+ * {@link LRUCache.OptionsBase.noUpdateTTL}
9345
+ */
9346
+ noUpdateTTL;
9347
+ /**
9348
+ * {@link LRUCache.OptionsBase.maxEntrySize}
9349
+ */
9350
+ maxEntrySize;
9351
+ /**
9352
+ * {@link LRUCache.OptionsBase.sizeCalculation}
9353
+ */
9354
+ sizeCalculation;
9355
+ /**
9356
+ * {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
9357
+ */
9358
+ noDeleteOnFetchRejection;
9359
+ /**
9360
+ * {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
9361
+ */
9362
+ noDeleteOnStaleGet;
9363
+ /**
9364
+ * {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
9365
+ */
9366
+ allowStaleOnFetchAbort;
9367
+ /**
9368
+ * {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
9369
+ */
9370
+ allowStaleOnFetchRejection;
9371
+ /**
9372
+ * {@link LRUCache.OptionsBase.ignoreFetchAbort}
9373
+ */
9374
+ ignoreFetchAbort;
9375
+ #size;
9376
+ #calculatedSize;
9377
+ #keyMap;
9378
+ #keyList;
9379
+ #valList;
9380
+ #next;
9381
+ #prev;
9382
+ #head;
9383
+ #tail;
9384
+ #free;
9385
+ #disposed;
9386
+ #sizes;
9387
+ #starts;
9388
+ #ttls;
9389
+ #autopurgeTimers;
9390
+ #hasDispose;
9391
+ #hasFetchMethod;
9392
+ #hasDisposeAfter;
9393
+ #hasOnInsert;
9394
+ /**
9395
+ * Do not call this method unless you need to inspect the
9396
+ * inner workings of the cache. If anything returned by this
9397
+ * object is modified in any way, strange breakage may occur.
9398
+ *
9399
+ * These fields are private for a reason!
9400
+ *
9401
+ * @internal
9402
+ */
9403
+ static unsafeExposeInternals(c) {
9404
+ return {
9405
+ starts: c.#starts,
9406
+ ttls: c.#ttls,
9407
+ autopurgeTimers: c.#autopurgeTimers,
9408
+ sizes: c.#sizes,
9409
+ keyMap: c.#keyMap,
9410
+ keyList: c.#keyList,
9411
+ valList: c.#valList,
9412
+ next: c.#next,
9413
+ prev: c.#prev,
9414
+ get head() {
9415
+ return c.#head;
9416
+ },
9417
+ get tail() {
9418
+ return c.#tail;
9419
+ },
9420
+ free: c.#free,
9421
+ isBackgroundFetch: (p) => c.#isBackgroundFetch(p),
9422
+ backgroundFetch: (k, index, options, context) => c.#backgroundFetch(k, index, options, context),
9423
+ moveToTail: (index) => c.#moveToTail(index),
9424
+ indexes: (options) => c.#indexes(options),
9425
+ rindexes: (options) => c.#rindexes(options),
9426
+ isStale: (index) => c.#isStale(index)
9427
+ };
9428
+ }
9429
+ /**
9430
+ * {@link LRUCache.OptionsBase.max} (read-only)
9431
+ */
9432
+ get max() {
9433
+ return this.#max;
9434
+ }
9435
+ /**
9436
+ * {@link LRUCache.OptionsBase.maxSize} (read-only)
9437
+ */
9438
+ get maxSize() {
9439
+ return this.#maxSize;
9440
+ }
9441
+ /**
9442
+ * The total computed size of items in the cache (read-only)
9443
+ */
9444
+ get calculatedSize() {
9445
+ return this.#calculatedSize;
9446
+ }
9447
+ /**
9448
+ * The number of items stored in the cache (read-only)
9449
+ */
9450
+ get size() {
9451
+ return this.#size;
9452
+ }
9453
+ /**
9454
+ * {@link LRUCache.OptionsBase.fetchMethod} (read-only)
9455
+ */
9456
+ get fetchMethod() {
9457
+ return this.#fetchMethod;
9458
+ }
9459
+ get memoMethod() {
9460
+ return this.#memoMethod;
9461
+ }
9462
+ /**
9463
+ * {@link LRUCache.OptionsBase.dispose} (read-only)
9464
+ */
9465
+ get dispose() {
9466
+ return this.#dispose;
9467
+ }
9468
+ /**
9469
+ * {@link LRUCache.OptionsBase.onInsert} (read-only)
9470
+ */
9471
+ get onInsert() {
9472
+ return this.#onInsert;
9473
+ }
9474
+ /**
9475
+ * {@link LRUCache.OptionsBase.disposeAfter} (read-only)
9476
+ */
9477
+ get disposeAfter() {
9478
+ return this.#disposeAfter;
9479
+ }
9480
+ constructor(options) {
9481
+ const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, onInsert, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, memoMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, perf } = options;
9482
+ if (perf !== void 0) {
9483
+ if (typeof perf?.now !== "function") throw new TypeError("perf option must have a now() method if specified");
9484
+ }
9485
+ this.#perf = perf ?? defaultPerf;
9486
+ if (max !== 0 && !isPosInt(max)) throw new TypeError("max option must be a nonnegative integer");
9487
+ const UintArray = max ? getUintArray(max) : Array;
9488
+ if (!UintArray) throw new Error("invalid max value: " + max);
9489
+ this.#max = max;
9490
+ this.#maxSize = maxSize;
9491
+ this.maxEntrySize = maxEntrySize || this.#maxSize;
9492
+ this.sizeCalculation = sizeCalculation;
9493
+ if (this.sizeCalculation) {
9494
+ if (!this.#maxSize && !this.maxEntrySize) throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");
9495
+ if (typeof this.sizeCalculation !== "function") throw new TypeError("sizeCalculation set to non-function");
9496
+ }
9497
+ if (memoMethod !== void 0 && typeof memoMethod !== "function") throw new TypeError("memoMethod must be a function if defined");
9498
+ this.#memoMethod = memoMethod;
9499
+ if (fetchMethod !== void 0 && typeof fetchMethod !== "function") throw new TypeError("fetchMethod must be a function if specified");
9500
+ this.#fetchMethod = fetchMethod;
9501
+ this.#hasFetchMethod = !!fetchMethod;
9502
+ this.#keyMap = /* @__PURE__ */ new Map();
9503
+ this.#keyList = new Array(max).fill(void 0);
9504
+ this.#valList = new Array(max).fill(void 0);
9505
+ this.#next = new UintArray(max);
9506
+ this.#prev = new UintArray(max);
9507
+ this.#head = 0;
9508
+ this.#tail = 0;
9509
+ this.#free = Stack.create(max);
9510
+ this.#size = 0;
9511
+ this.#calculatedSize = 0;
9512
+ if (typeof dispose === "function") this.#dispose = dispose;
9513
+ if (typeof onInsert === "function") this.#onInsert = onInsert;
9514
+ if (typeof disposeAfter === "function") {
9515
+ this.#disposeAfter = disposeAfter;
9516
+ this.#disposed = [];
9517
+ } else {
9518
+ this.#disposeAfter = void 0;
9519
+ this.#disposed = void 0;
9520
+ }
9521
+ this.#hasDispose = !!this.#dispose;
9522
+ this.#hasOnInsert = !!this.#onInsert;
9523
+ this.#hasDisposeAfter = !!this.#disposeAfter;
9524
+ this.noDisposeOnSet = !!noDisposeOnSet;
9525
+ this.noUpdateTTL = !!noUpdateTTL;
9526
+ this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection;
9527
+ this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection;
9528
+ this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort;
9529
+ this.ignoreFetchAbort = !!ignoreFetchAbort;
9530
+ if (this.maxEntrySize !== 0) {
9531
+ if (this.#maxSize !== 0) {
9532
+ if (!isPosInt(this.#maxSize)) throw new TypeError("maxSize must be a positive integer if specified");
9533
+ }
9534
+ if (!isPosInt(this.maxEntrySize)) throw new TypeError("maxEntrySize must be a positive integer if specified");
9535
+ this.#initializeSizeTracking();
9536
+ }
9537
+ this.allowStale = !!allowStale;
9538
+ this.noDeleteOnStaleGet = !!noDeleteOnStaleGet;
9539
+ this.updateAgeOnGet = !!updateAgeOnGet;
9540
+ this.updateAgeOnHas = !!updateAgeOnHas;
9541
+ this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1;
9542
+ this.ttlAutopurge = !!ttlAutopurge;
9543
+ this.ttl = ttl || 0;
9544
+ if (this.ttl) {
9545
+ if (!isPosInt(this.ttl)) throw new TypeError("ttl must be a positive integer if specified");
9546
+ this.#initializeTTLTracking();
9547
+ }
9548
+ if (this.#max === 0 && this.ttl === 0 && this.#maxSize === 0) throw new TypeError("At least one of max, maxSize, or ttl is required");
9549
+ if (!this.ttlAutopurge && !this.#max && !this.#maxSize) {
9550
+ const code = "LRU_CACHE_UNBOUNDED";
9551
+ if (shouldWarn(code)) {
9552
+ warned.add(code);
9553
+ emitWarning("TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.", "UnboundedCacheWarning", code, LRUCache);
9554
+ }
9555
+ }
9556
+ }
9557
+ /**
9558
+ * Return the number of ms left in the item's TTL. If item is not in cache,
9559
+ * returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
9560
+ */
9561
+ getRemainingTTL(key) {
9562
+ return this.#keyMap.has(key) ? Infinity : 0;
9563
+ }
9564
+ #initializeTTLTracking() {
9565
+ const ttls = new ZeroArray(this.#max);
9566
+ const starts = new ZeroArray(this.#max);
9567
+ this.#ttls = ttls;
9568
+ this.#starts = starts;
9569
+ const purgeTimers = this.ttlAutopurge ? new Array(this.#max) : void 0;
9570
+ this.#autopurgeTimers = purgeTimers;
9571
+ this.#setItemTTL = (index, ttl, start = this.#perf.now()) => {
9572
+ starts[index] = ttl !== 0 ? start : 0;
9573
+ ttls[index] = ttl;
9574
+ if (purgeTimers?.[index]) {
9575
+ clearTimeout(purgeTimers[index]);
9576
+ purgeTimers[index] = void 0;
9577
+ }
9578
+ if (ttl !== 0 && purgeTimers) {
9579
+ const t = setTimeout(() => {
9580
+ if (this.#isStale(index)) this.#delete(this.#keyList[index], "expire");
9581
+ }, ttl + 1);
9582
+ /* c8 ignore start */
9583
+ if (t.unref) t.unref();
9584
+ /* c8 ignore stop */
9585
+ purgeTimers[index] = t;
9586
+ }
9587
+ };
9588
+ this.#updateItemAge = (index) => {
9589
+ starts[index] = ttls[index] !== 0 ? this.#perf.now() : 0;
9590
+ };
9591
+ this.#statusTTL = (status, index) => {
9592
+ if (ttls[index]) {
9593
+ const ttl = ttls[index];
9594
+ const start = starts[index];
9595
+ /* c8 ignore next */
9596
+ if (!ttl || !start) return;
9597
+ status.ttl = ttl;
9598
+ status.start = start;
9599
+ status.now = cachedNow || getNow();
9600
+ status.remainingTTL = ttl - (status.now - start);
9601
+ }
9602
+ };
9603
+ let cachedNow = 0;
9604
+ const getNow = () => {
9605
+ const n = this.#perf.now();
9606
+ if (this.ttlResolution > 0) {
9607
+ cachedNow = n;
9608
+ const t = setTimeout(() => cachedNow = 0, this.ttlResolution);
9609
+ /* c8 ignore start */
9610
+ if (t.unref) t.unref();
9611
+ }
9612
+ return n;
9613
+ };
9614
+ this.getRemainingTTL = (key) => {
9615
+ const index = this.#keyMap.get(key);
9616
+ if (index === void 0) return 0;
9617
+ const ttl = ttls[index];
9618
+ const start = starts[index];
9619
+ if (!ttl || !start) return Infinity;
9620
+ return ttl - ((cachedNow || getNow()) - start);
9621
+ };
9622
+ this.#isStale = (index) => {
9623
+ const s = starts[index];
9624
+ const t = ttls[index];
9625
+ return !!t && !!s && (cachedNow || getNow()) - s > t;
9626
+ };
9627
+ }
9628
+ #updateItemAge = () => {};
9629
+ #statusTTL = () => {};
9630
+ #setItemTTL = () => {};
9631
+ /* c8 ignore stop */
9632
+ #isStale = () => false;
9633
+ #initializeSizeTracking() {
9634
+ const sizes = new ZeroArray(this.#max);
9635
+ this.#calculatedSize = 0;
9636
+ this.#sizes = sizes;
9637
+ this.#removeItemSize = (index) => {
9638
+ this.#calculatedSize -= sizes[index];
9639
+ sizes[index] = 0;
9640
+ };
9641
+ this.#requireSize = (k, v, size, sizeCalculation) => {
9642
+ if (this.#isBackgroundFetch(v)) return 0;
9643
+ if (!isPosInt(size)) if (sizeCalculation) {
9644
+ if (typeof sizeCalculation !== "function") throw new TypeError("sizeCalculation must be a function");
9645
+ size = sizeCalculation(v, k);
9646
+ if (!isPosInt(size)) throw new TypeError("sizeCalculation return invalid (expect positive integer)");
9647
+ } else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");
9648
+ return size;
9649
+ };
9650
+ this.#addItemSize = (index, size, status) => {
9651
+ sizes[index] = size;
9652
+ if (this.#maxSize) {
9653
+ const maxSize = this.#maxSize - sizes[index];
9654
+ while (this.#calculatedSize > maxSize) this.#evict(true);
9655
+ }
9656
+ this.#calculatedSize += sizes[index];
9657
+ if (status) {
9658
+ status.entrySize = size;
9659
+ status.totalCalculatedSize = this.#calculatedSize;
9660
+ }
9661
+ };
9662
+ }
9663
+ #removeItemSize = (_i) => {};
9664
+ #addItemSize = (_i, _s, _st) => {};
9665
+ #requireSize = (_k, _v, size, sizeCalculation) => {
9666
+ if (size || sizeCalculation) throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");
9667
+ return 0;
9668
+ };
9669
+ *#indexes({ allowStale = this.allowStale } = {}) {
9670
+ if (this.#size) for (let i = this.#tail;;) {
9671
+ if (!this.#isValidIndex(i)) break;
9672
+ if (allowStale || !this.#isStale(i)) yield i;
9673
+ if (i === this.#head) break;
9674
+ else i = this.#prev[i];
9675
+ }
9676
+ }
9677
+ *#rindexes({ allowStale = this.allowStale } = {}) {
9678
+ if (this.#size) for (let i = this.#head;;) {
9679
+ if (!this.#isValidIndex(i)) break;
9680
+ if (allowStale || !this.#isStale(i)) yield i;
9681
+ if (i === this.#tail) break;
9682
+ else i = this.#next[i];
9683
+ }
9684
+ }
9685
+ #isValidIndex(index) {
9686
+ return index !== void 0 && this.#keyMap.get(this.#keyList[index]) === index;
9687
+ }
9688
+ /**
9689
+ * Return a generator yielding `[key, value]` pairs,
9690
+ * in order from most recently used to least recently used.
9691
+ */
9692
+ *entries() {
9693
+ for (const i of this.#indexes()) if (this.#valList[i] !== void 0 && this.#keyList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield [this.#keyList[i], this.#valList[i]];
9694
+ }
9695
+ /**
9696
+ * Inverse order version of {@link LRUCache.entries}
9697
+ *
9698
+ * Return a generator yielding `[key, value]` pairs,
9699
+ * in order from least recently used to most recently used.
9700
+ */
9701
+ *rentries() {
9702
+ for (const i of this.#rindexes()) if (this.#valList[i] !== void 0 && this.#keyList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield [this.#keyList[i], this.#valList[i]];
9703
+ }
9704
+ /**
9705
+ * Return a generator yielding the keys in the cache,
9706
+ * in order from most recently used to least recently used.
9707
+ */
9708
+ *keys() {
9709
+ for (const i of this.#indexes()) {
9710
+ const k = this.#keyList[i];
9711
+ if (k !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield k;
9712
+ }
9713
+ }
9714
+ /**
9715
+ * Inverse order version of {@link LRUCache.keys}
9716
+ *
9717
+ * Return a generator yielding the keys in the cache,
9718
+ * in order from least recently used to most recently used.
9719
+ */
9720
+ *rkeys() {
9721
+ for (const i of this.#rindexes()) {
9722
+ const k = this.#keyList[i];
9723
+ if (k !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield k;
9724
+ }
9725
+ }
9726
+ /**
9727
+ * Return a generator yielding the values in the cache,
9728
+ * in order from most recently used to least recently used.
9729
+ */
9730
+ *values() {
9731
+ for (const i of this.#indexes()) if (this.#valList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield this.#valList[i];
9732
+ }
9733
+ /**
9734
+ * Inverse order version of {@link LRUCache.values}
9735
+ *
9736
+ * Return a generator yielding the values in the cache,
9737
+ * in order from least recently used to most recently used.
9738
+ */
9739
+ *rvalues() {
9740
+ for (const i of this.#rindexes()) if (this.#valList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield this.#valList[i];
9741
+ }
9742
+ /**
9743
+ * Iterating over the cache itself yields the same results as
9744
+ * {@link LRUCache.entries}
9745
+ */
9746
+ [Symbol.iterator]() {
9747
+ return this.entries();
9748
+ }
9749
+ /**
9750
+ * A String value that is used in the creation of the default string
9751
+ * description of an object. Called by the built-in method
9752
+ * `Object.prototype.toString`.
9753
+ */
9754
+ [Symbol.toStringTag] = "LRUCache";
9755
+ /**
9756
+ * Find a value for which the supplied fn method returns a truthy value,
9757
+ * similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
9758
+ */
9759
+ find(fn, getOptions = {}) {
9760
+ for (const i of this.#indexes()) {
9761
+ const v = this.#valList[i];
9762
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
9763
+ if (value === void 0) continue;
9764
+ if (fn(value, this.#keyList[i], this)) return this.get(this.#keyList[i], getOptions);
9765
+ }
9766
+ }
9767
+ /**
9768
+ * Call the supplied function on each item in the cache, in order from most
9769
+ * recently used to least recently used.
9770
+ *
9771
+ * `fn` is called as `fn(value, key, cache)`.
9772
+ *
9773
+ * If `thisp` is provided, function will be called in the `this`-context of
9774
+ * the provided object, or the cache if no `thisp` object is provided.
9775
+ *
9776
+ * Does not update age or recenty of use, or iterate over stale values.
9777
+ */
9778
+ forEach(fn, thisp = this) {
9779
+ for (const i of this.#indexes()) {
9780
+ const v = this.#valList[i];
9781
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
9782
+ if (value === void 0) continue;
9783
+ fn.call(thisp, value, this.#keyList[i], this);
9784
+ }
9785
+ }
9786
+ /**
9787
+ * The same as {@link LRUCache.forEach} but items are iterated over in
9788
+ * reverse order. (ie, less recently used items are iterated over first.)
9789
+ */
9790
+ rforEach(fn, thisp = this) {
9791
+ for (const i of this.#rindexes()) {
9792
+ const v = this.#valList[i];
9793
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
9794
+ if (value === void 0) continue;
9795
+ fn.call(thisp, value, this.#keyList[i], this);
9796
+ }
9797
+ }
9798
+ /**
9799
+ * Delete any stale entries. Returns true if anything was removed,
9800
+ * false otherwise.
9801
+ */
9802
+ purgeStale() {
9803
+ let deleted = false;
9804
+ for (const i of this.#rindexes({ allowStale: true })) if (this.#isStale(i)) {
9805
+ this.#delete(this.#keyList[i], "expire");
9806
+ deleted = true;
9807
+ }
9808
+ return deleted;
9809
+ }
9810
+ /**
9811
+ * Get the extended info about a given entry, to get its value, size, and
9812
+ * TTL info simultaneously. Returns `undefined` if the key is not present.
9813
+ *
9814
+ * Unlike {@link LRUCache#dump}, which is designed to be portable and survive
9815
+ * serialization, the `start` value is always the current timestamp, and the
9816
+ * `ttl` is a calculated remaining time to live (negative if expired).
9817
+ *
9818
+ * Always returns stale values, if their info is found in the cache, so be
9819
+ * sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
9820
+ * if relevant.
9821
+ */
9822
+ info(key) {
9823
+ const i = this.#keyMap.get(key);
9824
+ if (i === void 0) return void 0;
9825
+ const v = this.#valList[i];
9826
+ /* c8 ignore start - this isn't tested for the info function,
9827
+ * but it's the same logic as found in other places. */
9828
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
9829
+ if (value === void 0) return void 0;
9830
+ /* c8 ignore end */
9831
+ const entry = { value };
9832
+ if (this.#ttls && this.#starts) {
9833
+ const ttl = this.#ttls[i];
9834
+ const start = this.#starts[i];
9835
+ if (ttl && start) {
9836
+ entry.ttl = ttl - (this.#perf.now() - start);
9837
+ entry.start = Date.now();
9838
+ }
9839
+ }
9840
+ if (this.#sizes) entry.size = this.#sizes[i];
9841
+ return entry;
9842
+ }
9843
+ /**
9844
+ * Return an array of [key, {@link LRUCache.Entry}] tuples which can be
9845
+ * passed to {@link LRUCache#load}.
9846
+ *
9847
+ * The `start` fields are calculated relative to a portable `Date.now()`
9848
+ * timestamp, even if `performance.now()` is available.
9849
+ *
9850
+ * Stale entries are always included in the `dump`, even if
9851
+ * {@link LRUCache.OptionsBase.allowStale} is false.
9852
+ *
9853
+ * Note: this returns an actual array, not a generator, so it can be more
9854
+ * easily passed around.
9855
+ */
9856
+ dump() {
9857
+ const arr = [];
9858
+ for (const i of this.#indexes({ allowStale: true })) {
9859
+ const key = this.#keyList[i];
9860
+ const v = this.#valList[i];
9861
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
9862
+ if (value === void 0 || key === void 0) continue;
9863
+ const entry = { value };
9864
+ if (this.#ttls && this.#starts) {
9865
+ entry.ttl = this.#ttls[i];
9866
+ const age = this.#perf.now() - this.#starts[i];
9867
+ entry.start = Math.floor(Date.now() - age);
9868
+ }
9869
+ if (this.#sizes) entry.size = this.#sizes[i];
9870
+ arr.unshift([key, entry]);
9871
+ }
9872
+ return arr;
9873
+ }
9874
+ /**
9875
+ * Reset the cache and load in the items in entries in the order listed.
9876
+ *
9877
+ * The shape of the resulting cache may be different if the same options are
9878
+ * not used in both caches.
9879
+ *
9880
+ * The `start` fields are assumed to be calculated relative to a portable
9881
+ * `Date.now()` timestamp, even if `performance.now()` is available.
9882
+ */
9883
+ load(arr) {
9884
+ this.clear();
9885
+ for (const [key, entry] of arr) {
9886
+ if (entry.start) {
9887
+ const age = Date.now() - entry.start;
9888
+ entry.start = this.#perf.now() - age;
9889
+ }
9890
+ this.set(key, entry.value, entry);
9891
+ }
9892
+ }
9893
+ /**
9894
+ * Add a value to the cache.
9895
+ *
9896
+ * Note: if `undefined` is specified as a value, this is an alias for
9897
+ * {@link LRUCache#delete}
9898
+ *
9899
+ * Fields on the {@link LRUCache.SetOptions} options param will override
9900
+ * their corresponding values in the constructor options for the scope
9901
+ * of this single `set()` operation.
9902
+ *
9903
+ * If `start` is provided, then that will set the effective start
9904
+ * time for the TTL calculation. Note that this must be a previous
9905
+ * value of `performance.now()` if supported, or a previous value of
9906
+ * `Date.now()` if not.
9907
+ *
9908
+ * Options object may also include `size`, which will prevent
9909
+ * calling the `sizeCalculation` function and just use the specified
9910
+ * number if it is a positive integer, and `noDisposeOnSet` which
9911
+ * will prevent calling a `dispose` function in the case of
9912
+ * overwrites.
9913
+ *
9914
+ * If the `size` (or return value of `sizeCalculation`) for a given
9915
+ * entry is greater than `maxEntrySize`, then the item will not be
9916
+ * added to the cache.
9917
+ *
9918
+ * Will update the recency of the entry.
9919
+ *
9920
+ * If the value is `undefined`, then this is an alias for
9921
+ * `cache.delete(key)`. `undefined` is never stored in the cache.
9922
+ */
9923
+ set(k, v, setOptions = {}) {
9924
+ if (v === void 0) {
9925
+ this.delete(k);
9926
+ return this;
9927
+ }
9928
+ const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status } = setOptions;
9929
+ let { noUpdateTTL = this.noUpdateTTL } = setOptions;
9930
+ const size = this.#requireSize(k, v, setOptions.size || 0, sizeCalculation);
9931
+ if (this.maxEntrySize && size > this.maxEntrySize) {
9932
+ if (status) {
9933
+ status.set = "miss";
9934
+ status.maxEntrySizeExceeded = true;
9935
+ }
9936
+ this.#delete(k, "set");
9937
+ return this;
9938
+ }
9939
+ let index = this.#size === 0 ? void 0 : this.#keyMap.get(k);
9940
+ if (index === void 0) {
9941
+ index = this.#size === 0 ? this.#tail : this.#free.length !== 0 ? this.#free.pop() : this.#size === this.#max ? this.#evict(false) : this.#size;
9942
+ this.#keyList[index] = k;
9943
+ this.#valList[index] = v;
9944
+ this.#keyMap.set(k, index);
9945
+ this.#next[this.#tail] = index;
9946
+ this.#prev[index] = this.#tail;
9947
+ this.#tail = index;
9948
+ this.#size++;
9949
+ this.#addItemSize(index, size, status);
9950
+ if (status) status.set = "add";
9951
+ noUpdateTTL = false;
9952
+ if (this.#hasOnInsert) this.#onInsert?.(v, k, "add");
9953
+ } else {
9954
+ this.#moveToTail(index);
9955
+ const oldVal = this.#valList[index];
9956
+ if (v !== oldVal) {
9957
+ if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) {
9958
+ oldVal.__abortController.abort(/* @__PURE__ */ new Error("replaced"));
9959
+ const { __staleWhileFetching: s } = oldVal;
9960
+ if (s !== void 0 && !noDisposeOnSet) {
9961
+ if (this.#hasDispose) this.#dispose?.(s, k, "set");
9962
+ if (this.#hasDisposeAfter) this.#disposed?.push([
9963
+ s,
9964
+ k,
9965
+ "set"
9966
+ ]);
9967
+ }
9968
+ } else if (!noDisposeOnSet) {
9969
+ if (this.#hasDispose) this.#dispose?.(oldVal, k, "set");
9970
+ if (this.#hasDisposeAfter) this.#disposed?.push([
9971
+ oldVal,
9972
+ k,
9973
+ "set"
9974
+ ]);
9975
+ }
9976
+ this.#removeItemSize(index);
9977
+ this.#addItemSize(index, size, status);
9978
+ this.#valList[index] = v;
9979
+ if (status) {
9980
+ status.set = "replace";
9981
+ const oldValue = oldVal && this.#isBackgroundFetch(oldVal) ? oldVal.__staleWhileFetching : oldVal;
9982
+ if (oldValue !== void 0) status.oldValue = oldValue;
9983
+ }
9984
+ } else if (status) status.set = "update";
9985
+ if (this.#hasOnInsert) this.onInsert?.(v, k, v === oldVal ? "update" : "replace");
9986
+ }
9987
+ if (ttl !== 0 && !this.#ttls) this.#initializeTTLTracking();
9988
+ if (this.#ttls) {
9989
+ if (!noUpdateTTL) this.#setItemTTL(index, ttl, start);
9990
+ if (status) this.#statusTTL(status, index);
9991
+ }
9992
+ if (!noDisposeOnSet && this.#hasDisposeAfter && this.#disposed) {
9993
+ const dt = this.#disposed;
9994
+ let task;
9995
+ while (task = dt?.shift()) this.#disposeAfter?.(...task);
9996
+ }
9997
+ return this;
9998
+ }
9999
+ /**
10000
+ * Evict the least recently used item, returning its value or
10001
+ * `undefined` if cache is empty.
10002
+ */
10003
+ pop() {
10004
+ try {
10005
+ while (this.#size) {
10006
+ const val = this.#valList[this.#head];
10007
+ this.#evict(true);
10008
+ if (this.#isBackgroundFetch(val)) {
10009
+ if (val.__staleWhileFetching) return val.__staleWhileFetching;
10010
+ } else if (val !== void 0) return val;
10011
+ }
10012
+ } finally {
10013
+ if (this.#hasDisposeAfter && this.#disposed) {
10014
+ const dt = this.#disposed;
10015
+ let task;
10016
+ while (task = dt?.shift()) this.#disposeAfter?.(...task);
10017
+ }
10018
+ }
10019
+ }
10020
+ #evict(free) {
10021
+ const head = this.#head;
10022
+ const k = this.#keyList[head];
10023
+ const v = this.#valList[head];
10024
+ if (this.#hasFetchMethod && this.#isBackgroundFetch(v)) v.__abortController.abort(/* @__PURE__ */ new Error("evicted"));
10025
+ else if (this.#hasDispose || this.#hasDisposeAfter) {
10026
+ if (this.#hasDispose) this.#dispose?.(v, k, "evict");
10027
+ if (this.#hasDisposeAfter) this.#disposed?.push([
10028
+ v,
10029
+ k,
10030
+ "evict"
10031
+ ]);
10032
+ }
10033
+ this.#removeItemSize(head);
10034
+ if (this.#autopurgeTimers?.[head]) {
10035
+ clearTimeout(this.#autopurgeTimers[head]);
10036
+ this.#autopurgeTimers[head] = void 0;
10037
+ }
10038
+ if (free) {
10039
+ this.#keyList[head] = void 0;
10040
+ this.#valList[head] = void 0;
10041
+ this.#free.push(head);
10042
+ }
10043
+ if (this.#size === 1) {
10044
+ this.#head = this.#tail = 0;
10045
+ this.#free.length = 0;
10046
+ } else this.#head = this.#next[head];
10047
+ this.#keyMap.delete(k);
10048
+ this.#size--;
10049
+ return head;
10050
+ }
10051
+ /**
10052
+ * Check if a key is in the cache, without updating the recency of use.
10053
+ * Will return false if the item is stale, even though it is technically
10054
+ * in the cache.
10055
+ *
10056
+ * Check if a key is in the cache, without updating the recency of
10057
+ * use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
10058
+ * to `true` in either the options or the constructor.
10059
+ *
10060
+ * Will return `false` if the item is stale, even though it is technically in
10061
+ * the cache. The difference can be determined (if it matters) by using a
10062
+ * `status` argument, and inspecting the `has` field.
10063
+ *
10064
+ * Will not update item age unless
10065
+ * {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
10066
+ */
10067
+ has(k, hasOptions = {}) {
10068
+ const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions;
10069
+ const index = this.#keyMap.get(k);
10070
+ if (index !== void 0) {
10071
+ const v = this.#valList[index];
10072
+ if (this.#isBackgroundFetch(v) && v.__staleWhileFetching === void 0) return false;
10073
+ if (!this.#isStale(index)) {
10074
+ if (updateAgeOnHas) this.#updateItemAge(index);
10075
+ if (status) {
10076
+ status.has = "hit";
10077
+ this.#statusTTL(status, index);
10078
+ }
10079
+ return true;
10080
+ } else if (status) {
10081
+ status.has = "stale";
10082
+ this.#statusTTL(status, index);
10083
+ }
10084
+ } else if (status) status.has = "miss";
10085
+ return false;
10086
+ }
10087
+ /**
10088
+ * Like {@link LRUCache#get} but doesn't update recency or delete stale
10089
+ * items.
10090
+ *
10091
+ * Returns `undefined` if the item is stale, unless
10092
+ * {@link LRUCache.OptionsBase.allowStale} is set.
10093
+ */
10094
+ peek(k, peekOptions = {}) {
10095
+ const { allowStale = this.allowStale } = peekOptions;
10096
+ const index = this.#keyMap.get(k);
10097
+ if (index === void 0 || !allowStale && this.#isStale(index)) return;
10098
+ const v = this.#valList[index];
10099
+ return this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
10100
+ }
10101
+ #backgroundFetch(k, index, options, context) {
10102
+ const v = index === void 0 ? void 0 : this.#valList[index];
10103
+ if (this.#isBackgroundFetch(v)) return v;
10104
+ const ac = new AC();
10105
+ const { signal } = options;
10106
+ signal?.addEventListener("abort", () => ac.abort(signal.reason), { signal: ac.signal });
10107
+ const fetchOpts = {
10108
+ signal: ac.signal,
10109
+ options,
10110
+ context
10111
+ };
10112
+ const cb = (v, updateCache = false) => {
10113
+ const { aborted } = ac.signal;
10114
+ const ignoreAbort = options.ignoreFetchAbort && v !== void 0;
10115
+ if (options.status) if (aborted && !updateCache) {
10116
+ options.status.fetchAborted = true;
10117
+ options.status.fetchError = ac.signal.reason;
10118
+ if (ignoreAbort) options.status.fetchAbortIgnored = true;
10119
+ } else options.status.fetchResolved = true;
10120
+ if (aborted && !ignoreAbort && !updateCache) return fetchFail(ac.signal.reason);
10121
+ const bf = p;
10122
+ const vl = this.#valList[index];
10123
+ if (vl === p || ignoreAbort && updateCache && vl === void 0) if (v === void 0) if (bf.__staleWhileFetching !== void 0) this.#valList[index] = bf.__staleWhileFetching;
10124
+ else this.#delete(k, "fetch");
10125
+ else {
10126
+ if (options.status) options.status.fetchUpdated = true;
10127
+ this.set(k, v, fetchOpts.options);
10128
+ }
10129
+ return v;
10130
+ };
10131
+ const eb = (er) => {
10132
+ if (options.status) {
10133
+ options.status.fetchRejected = true;
10134
+ options.status.fetchError = er;
10135
+ }
10136
+ return fetchFail(er);
10137
+ };
10138
+ const fetchFail = (er) => {
10139
+ const { aborted } = ac.signal;
10140
+ const allowStaleAborted = aborted && options.allowStaleOnFetchAbort;
10141
+ const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection;
10142
+ const noDelete = allowStale || options.noDeleteOnFetchRejection;
10143
+ const bf = p;
10144
+ if (this.#valList[index] === p) {
10145
+ if (!noDelete || bf.__staleWhileFetching === void 0) this.#delete(k, "fetch");
10146
+ else if (!allowStaleAborted) this.#valList[index] = bf.__staleWhileFetching;
10147
+ }
10148
+ if (allowStale) {
10149
+ if (options.status && bf.__staleWhileFetching !== void 0) options.status.returnedStale = true;
10150
+ return bf.__staleWhileFetching;
10151
+ } else if (bf.__returned === bf) throw er;
10152
+ };
10153
+ const pcall = (res, rej) => {
10154
+ const fmp = this.#fetchMethod?.(k, v, fetchOpts);
10155
+ if (fmp && fmp instanceof Promise) fmp.then((v) => res(v === void 0 ? void 0 : v), rej);
10156
+ ac.signal.addEventListener("abort", () => {
10157
+ if (!options.ignoreFetchAbort || options.allowStaleOnFetchAbort) {
10158
+ res(void 0);
10159
+ if (options.allowStaleOnFetchAbort) res = (v) => cb(v, true);
10160
+ }
10161
+ });
10162
+ };
10163
+ if (options.status) options.status.fetchDispatched = true;
10164
+ const p = new Promise(pcall).then(cb, eb);
10165
+ const bf = Object.assign(p, {
10166
+ __abortController: ac,
10167
+ __staleWhileFetching: v,
10168
+ __returned: void 0
10169
+ });
10170
+ if (index === void 0) {
10171
+ this.set(k, bf, {
10172
+ ...fetchOpts.options,
10173
+ status: void 0
10174
+ });
10175
+ index = this.#keyMap.get(k);
10176
+ } else this.#valList[index] = bf;
10177
+ return bf;
10178
+ }
10179
+ #isBackgroundFetch(p) {
10180
+ if (!this.#hasFetchMethod) return false;
10181
+ const b = p;
10182
+ return !!b && b instanceof Promise && b.hasOwnProperty("__staleWhileFetching") && b.__abortController instanceof AC;
10183
+ }
10184
+ async fetch(k, fetchOptions = {}) {
10185
+ const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL, noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal } = fetchOptions;
10186
+ if (!this.#hasFetchMethod) {
10187
+ if (status) status.fetch = "get";
10188
+ return this.get(k, {
10189
+ allowStale,
10190
+ updateAgeOnGet,
10191
+ noDeleteOnStaleGet,
10192
+ status
10193
+ });
10194
+ }
10195
+ const options = {
10196
+ allowStale,
10197
+ updateAgeOnGet,
10198
+ noDeleteOnStaleGet,
10199
+ ttl,
10200
+ noDisposeOnSet,
10201
+ size,
10202
+ sizeCalculation,
10203
+ noUpdateTTL,
10204
+ noDeleteOnFetchRejection,
10205
+ allowStaleOnFetchRejection,
10206
+ allowStaleOnFetchAbort,
10207
+ ignoreFetchAbort,
10208
+ status,
10209
+ signal
10210
+ };
10211
+ let index = this.#keyMap.get(k);
10212
+ if (index === void 0) {
10213
+ if (status) status.fetch = "miss";
10214
+ const p = this.#backgroundFetch(k, index, options, context);
10215
+ return p.__returned = p;
10216
+ } else {
10217
+ const v = this.#valList[index];
10218
+ if (this.#isBackgroundFetch(v)) {
10219
+ const stale = allowStale && v.__staleWhileFetching !== void 0;
10220
+ if (status) {
10221
+ status.fetch = "inflight";
10222
+ if (stale) status.returnedStale = true;
10223
+ }
10224
+ return stale ? v.__staleWhileFetching : v.__returned = v;
10225
+ }
10226
+ const isStale = this.#isStale(index);
10227
+ if (!forceRefresh && !isStale) {
10228
+ if (status) status.fetch = "hit";
10229
+ this.#moveToTail(index);
10230
+ if (updateAgeOnGet) this.#updateItemAge(index);
10231
+ if (status) this.#statusTTL(status, index);
10232
+ return v;
10233
+ }
10234
+ const p = this.#backgroundFetch(k, index, options, context);
10235
+ const staleVal = p.__staleWhileFetching !== void 0 && allowStale;
10236
+ if (status) {
10237
+ status.fetch = isStale ? "stale" : "refresh";
10238
+ if (staleVal && isStale) status.returnedStale = true;
10239
+ }
10240
+ return staleVal ? p.__staleWhileFetching : p.__returned = p;
10241
+ }
10242
+ }
10243
+ async forceFetch(k, fetchOptions = {}) {
10244
+ const v = await this.fetch(k, fetchOptions);
10245
+ if (v === void 0) throw new Error("fetch() returned undefined");
10246
+ return v;
10247
+ }
10248
+ memo(k, memoOptions = {}) {
10249
+ const memoMethod = this.#memoMethod;
10250
+ if (!memoMethod) throw new Error("no memoMethod provided to constructor");
10251
+ const { context, forceRefresh, ...options } = memoOptions;
10252
+ const v = this.get(k, options);
10253
+ if (!forceRefresh && v !== void 0) return v;
10254
+ const vv = memoMethod(k, v, {
10255
+ options,
10256
+ context
10257
+ });
10258
+ this.set(k, vv, options);
10259
+ return vv;
10260
+ }
10261
+ /**
10262
+ * Return a value from the cache. Will update the recency of the cache
10263
+ * entry found.
10264
+ *
10265
+ * If the key is not found, get() will return `undefined`.
10266
+ */
10267
+ get(k, getOptions = {}) {
10268
+ const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status } = getOptions;
10269
+ const index = this.#keyMap.get(k);
10270
+ if (index !== void 0) {
10271
+ const value = this.#valList[index];
10272
+ const fetching = this.#isBackgroundFetch(value);
10273
+ if (status) this.#statusTTL(status, index);
10274
+ if (this.#isStale(index)) {
10275
+ if (status) status.get = "stale";
10276
+ if (!fetching) {
10277
+ if (!noDeleteOnStaleGet) this.#delete(k, "expire");
10278
+ if (status && allowStale) status.returnedStale = true;
10279
+ return allowStale ? value : void 0;
10280
+ } else {
10281
+ if (status && allowStale && value.__staleWhileFetching !== void 0) status.returnedStale = true;
10282
+ return allowStale ? value.__staleWhileFetching : void 0;
10283
+ }
10284
+ } else {
10285
+ if (status) status.get = "hit";
10286
+ if (fetching) return value.__staleWhileFetching;
10287
+ this.#moveToTail(index);
10288
+ if (updateAgeOnGet) this.#updateItemAge(index);
10289
+ return value;
10290
+ }
10291
+ } else if (status) status.get = "miss";
10292
+ }
10293
+ #connect(p, n) {
10294
+ this.#prev[n] = p;
10295
+ this.#next[p] = n;
10296
+ }
10297
+ #moveToTail(index) {
10298
+ if (index !== this.#tail) {
10299
+ if (index === this.#head) this.#head = this.#next[index];
10300
+ else this.#connect(this.#prev[index], this.#next[index]);
10301
+ this.#connect(this.#tail, index);
10302
+ this.#tail = index;
10303
+ }
10304
+ }
10305
+ /**
10306
+ * Deletes a key out of the cache.
10307
+ *
10308
+ * Returns true if the key was deleted, false otherwise.
10309
+ */
10310
+ delete(k) {
10311
+ return this.#delete(k, "delete");
10312
+ }
10313
+ #delete(k, reason) {
10314
+ let deleted = false;
10315
+ if (this.#size !== 0) {
10316
+ const index = this.#keyMap.get(k);
10317
+ if (index !== void 0) {
10318
+ if (this.#autopurgeTimers?.[index]) {
10319
+ clearTimeout(this.#autopurgeTimers?.[index]);
10320
+ this.#autopurgeTimers[index] = void 0;
10321
+ }
10322
+ deleted = true;
10323
+ if (this.#size === 1) this.#clear(reason);
10324
+ else {
10325
+ this.#removeItemSize(index);
10326
+ const v = this.#valList[index];
10327
+ if (this.#isBackgroundFetch(v)) v.__abortController.abort(/* @__PURE__ */ new Error("deleted"));
10328
+ else if (this.#hasDispose || this.#hasDisposeAfter) {
10329
+ if (this.#hasDispose) this.#dispose?.(v, k, reason);
10330
+ if (this.#hasDisposeAfter) this.#disposed?.push([
10331
+ v,
10332
+ k,
10333
+ reason
10334
+ ]);
10335
+ }
10336
+ this.#keyMap.delete(k);
10337
+ this.#keyList[index] = void 0;
10338
+ this.#valList[index] = void 0;
10339
+ if (index === this.#tail) this.#tail = this.#prev[index];
10340
+ else if (index === this.#head) this.#head = this.#next[index];
10341
+ else {
10342
+ const pi = this.#prev[index];
10343
+ this.#next[pi] = this.#next[index];
10344
+ const ni = this.#next[index];
10345
+ this.#prev[ni] = this.#prev[index];
10346
+ }
10347
+ this.#size--;
10348
+ this.#free.push(index);
10349
+ }
10350
+ }
10351
+ }
10352
+ if (this.#hasDisposeAfter && this.#disposed?.length) {
10353
+ const dt = this.#disposed;
10354
+ let task;
10355
+ while (task = dt?.shift()) this.#disposeAfter?.(...task);
10356
+ }
10357
+ return deleted;
10358
+ }
10359
+ /**
10360
+ * Clear the cache entirely, throwing away all values.
10361
+ */
10362
+ clear() {
10363
+ return this.#clear("delete");
10364
+ }
10365
+ #clear(reason) {
10366
+ for (const index of this.#rindexes({ allowStale: true })) {
10367
+ const v = this.#valList[index];
10368
+ if (this.#isBackgroundFetch(v)) v.__abortController.abort(/* @__PURE__ */ new Error("deleted"));
10369
+ else {
10370
+ const k = this.#keyList[index];
10371
+ if (this.#hasDispose) this.#dispose?.(v, k, reason);
10372
+ if (this.#hasDisposeAfter) this.#disposed?.push([
10373
+ v,
10374
+ k,
10375
+ reason
10376
+ ]);
10377
+ }
10378
+ }
10379
+ this.#keyMap.clear();
10380
+ this.#valList.fill(void 0);
10381
+ this.#keyList.fill(void 0);
10382
+ if (this.#ttls && this.#starts) {
10383
+ this.#ttls.fill(0);
10384
+ this.#starts.fill(0);
10385
+ for (const t of this.#autopurgeTimers ?? []) if (t !== void 0) clearTimeout(t);
10386
+ this.#autopurgeTimers?.fill(void 0);
10387
+ }
10388
+ if (this.#sizes) this.#sizes.fill(0);
10389
+ this.#head = 0;
10390
+ this.#tail = 0;
10391
+ this.#free.length = 0;
10392
+ this.#calculatedSize = 0;
10393
+ this.#size = 0;
10394
+ if (this.#hasDisposeAfter && this.#disposed) {
10395
+ const dt = this.#disposed;
10396
+ let task;
10397
+ while (task = dt?.shift()) this.#disposeAfter?.(...task);
10398
+ }
10399
+ }
10400
+ };
10401
+ //#endregion
10402
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column_providers/providers.js
10403
+ /**
10404
+ * Unified memoised factory dispatching to the right provider flavour by the
10405
+ * source shape:
10406
+ * - `TreeNodeAccessor` → {@link AccessorColumnsProvider}
10407
+ * (indexed by `root.handle`, walks the accessor tree once per root).
10408
+ * - `UpstreamBlockCtx<AccessorHandle>[]` (or omitted — pulled from the
10409
+ * ambient ctx) → {@link ResultPoolColumnsProvider}
10410
+ * (indexed by a content-hash of the block list).
10411
+ *
10412
+ * Both branches return cached instances within their LRU window, so repeated
10413
+ * calls with the same source skip re-walking / re-hashing.
10414
+ */
10415
+ function ColumnsProvider(source) {
10416
+ if (isNil(source) || Array.isArray(source)) return ResultPoolColumnsProvider(source);
10417
+ else if (source instanceof TreeNodeAccessor) return AccessorColumnsProvider(source);
10418
+ else throw new Error("Unknown columns provider source");
10419
+ }
10420
+ /**
10421
+ * Memoised constructor — same `root.handle` returns the same
10422
+ * {@link AccessorColumnsProviderImpl}, so `indexAccessorRoot` runs once per
10423
+ * accessor root (within the LRU window).
10424
+ */
10425
+ const _accessorProviderCache = new LRUCache({ max: 64 });
10426
+ function AccessorColumnsProvider(root) {
10427
+ let provider = _accessorProviderCache.get(root.handle);
10428
+ if (provider === void 0) {
10429
+ provider = new AccessorColumnsProviderImpl(root);
10430
+ _accessorProviderCache.set(root.handle, provider);
10431
+ }
10432
+ return provider;
10433
+ }
10434
+ /**
10435
+ * Memoised constructor — same `rawPool` content returns the same
10436
+ * {@link ResultPoolColumnsProviderImpl}, so `indexPoolBlock` runs once per
10437
+ * pool snapshot (within the LRU window).
10438
+ */
10439
+ const _resultPoolProviderCache = new LRUCache({ max: 4 });
10440
+ function ResultPoolColumnsProvider(rawPool = getCfgRenderCtx().getUpstreamBlockCtx()) {
10441
+ const key = hashRawPool(rawPool);
10442
+ let provider = _resultPoolProviderCache.get(key);
10443
+ if (provider === void 0) {
10444
+ provider = new ResultPoolColumnsProviderImpl(rawPool);
10445
+ _resultPoolProviderCache.set(key, provider);
10446
+ }
10447
+ return provider;
10448
+ }
10449
+ /**
10450
+ * Sandbox-specific provider over a {@link TreeNodeAccessor} root. Uses the
10451
+ * accessor's own `resolvePath` as the canonical root path for id construction,
10452
+ * and adds `getColumns()` returning {@link ColumnLazy}s on top of the generic
10453
+ * entries index.
10454
+ */
10455
+ var AccessorColumnsProviderImpl = class extends AccessorEntriesProvider {
10456
+ cachedColumns;
10457
+ constructor(root) {
10458
+ super(root, root.resolvePath);
10459
+ }
10460
+ getColumns() {
10461
+ if (this.cachedColumns !== void 0) return this.cachedColumns;
10462
+ return this.cachedColumns = Array.from(this.entries.values()).map((e) => ColumnLazyImpl.fromAccessor(e)).filter((v) => !isNil(v));
10463
+ }
10464
+ };
10465
+ /**
10466
+ * Sandbox-specific result-pool provider. Accepts the raw handle-shaped blocks
10467
+ * returned by {@link GlobalCfgRenderCtxMethods.getUpstreamBlockCtx} and
10468
+ * wraps them into {@link TreeNodeAccessor}s, then adds `getColumns()`.
10469
+ */
10470
+ var ResultPoolColumnsProviderImpl = class extends ResultPoolEntriesProvider {
10471
+ cachedColumns;
10472
+ constructor(rawPool = getCfgRenderCtx().getUpstreamBlockCtx()) {
10473
+ const blocks = rawPool.map((b) => ({
10474
+ blockId: b.blockId,
10475
+ prodCtx: b.prodCtx !== void 0 ? new TreeNodeAccessor(b.prodCtx, [b.blockId, "prodCtx"]) : void 0,
10476
+ stagingCtx: b.stagingCtx !== void 0 ? new TreeNodeAccessor(b.stagingCtx, [b.blockId, "stagingCtx"]) : void 0,
10477
+ prodIncomplete: b.prodIncomplete,
10478
+ stagingIncomplete: b.stagingIncomplete
10479
+ }));
10480
+ super(blocks);
10481
+ }
10482
+ getColumns() {
10483
+ if (this.cachedColumns !== void 0) return this.cachedColumns;
10484
+ return this.cachedColumns = Array.from(this.getPObjectEntries().values()).map((e) => ColumnLazyImpl.fromAccessor(e)).filter((v) => !isNil(v));
10485
+ }
10486
+ };
10487
+ function hashRawPool(rawPool) {
10488
+ return rawPool.map((b) => `${b.blockId}\x1f${b.prodCtx ?? ""}\x1f${b.stagingCtx ?? ""}\x1f${b.prodIncomplete ? 1 : 0}\x1f${b.stagingIncomplete ? 1 : 0}`).join("");
10489
+ }
10490
+ //#endregion
10491
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column_providers/index.js
10492
+ /**
10493
+ * Build the default set of ColumnsProviders for the ambient render ctx:
10494
+ * - `AccessorColumnsProvider` over `outputs` (if present)
10495
+ * - `AccessorColumnsProvider` over `prerun` (if present)
10496
+ * - `ResultPoolColumnsProvider` over `rawResultPool`
10497
+ *
10498
+ * Pulls handles directly from the ambient `cfgRenderCtx`. Returns `[]` when
10499
+ * called outside a render context.
10500
+ *
10501
+ * Result is memoised per-ctx (WeakMap → array). Repeated calls within the
10502
+ * same render cycle return the same provider triplet — inner providers are
10503
+ * also LRU-memoised by their content keys, so even a cache miss here doesn't
10504
+ * re-walk the trees.
10505
+ */
10506
+ const _ctxProvidersCache = /* @__PURE__ */ new WeakMap();
10507
+ function getCtxProviders(deps) {
10508
+ const ctx = deps?.ctx ?? getCfgRenderCtx();
10509
+ const cached = _ctxProvidersCache.get(ctx);
10510
+ if (cached !== void 0) return cached;
10511
+ const providers = [];
10512
+ const outputs = ctx.getAccessorHandleByName(MainAccessorName);
10513
+ if (outputs !== void 0) providers.push(ColumnsProvider(new TreeNodeAccessor(outputs, [MainAccessorName])));
10514
+ const prerun = ctx.getAccessorHandleByName(StagingAccessorName);
10515
+ if (prerun !== void 0) providers.push(ColumnsProvider(new TreeNodeAccessor(prerun, [StagingAccessorName])));
10516
+ providers.push(ColumnsProvider(ctx.getUpstreamBlockCtx()));
10517
+ _ctxProvidersCache.set(ctx, providers);
10518
+ return providers;
10519
+ }
10520
+ function isColumnProvider(source) {
10521
+ if (typeof source !== "object" || source === null) return false;
10522
+ const p = source;
10523
+ return typeof p.getColumns === "function" && typeof p.isFinal === "function";
10524
+ }
10525
+ //#endregion
10526
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column_lazy.js
10527
+ /**
10528
+ * Thrown by leaf-recipe factories when the requested column is provably
10529
+ * absent in the active render ctx — i.e. every relevant accessor reports
10530
+ * `inputsLocked` and the column did not appear. Distinct from the
10531
+ * `undefined` return that the factories still use for the "resolving" case
10532
+ * (the column may still appear later).
10533
+ *
10534
+ * Catch at the boundary (resolver / filter+sort wiring / data-table assembly)
10535
+ * when partial absence should be surfaced to the user rather than silently
10536
+ * producing an empty result.
10537
+ */
10538
+ var ColumnAbsentError = class extends Error {
10539
+ id;
10540
+ constructor(id) {
10541
+ super(`Column is absent in the active render ctx and will not appear: ${id}`);
10542
+ this.id = id;
10543
+ this.name = "ColumnAbsentError";
10544
+ }
10545
+ };
10546
+ /**
10547
+ * ColumnLazy is the leaf-recipe building block: a {@link ColumnRecipe} whose
10548
+ * `id` is a bare {@link PObjectId} and whose readers are bound to a single
10549
+ * tree-accessor leaf. Layered encodings (Overridden / Discovered / Filtered)
10550
+ * are reified through their dedicated recipe classes and reference leaf
10551
+ * columns by id.
10552
+ */
10553
+ var ColumnLazyImpl = class ColumnLazyImpl {
10554
+ id;
10555
+ options;
10556
+ specCache;
10557
+ dataCache;
10558
+ dataStatusCache;
10559
+ constructor(id, options) {
10560
+ this.id = id;
10561
+ this.options = options;
10562
+ }
10563
+ /** A leaf-recipe references exactly one column — its own id. */
10564
+ getReferencedIds() {
10565
+ return [this.id];
10566
+ }
10567
+ getSpec() {
10568
+ if (this.specCache === void 0) this.specCache = { value: this.options.getSpec() };
10569
+ return this.specCache.value;
10570
+ }
10571
+ /** Leaf-shaped — points straight at `this.id`. */
10572
+ getQuery() {
10573
+ return {
10574
+ type: "column",
10575
+ column: this.id
10576
+ };
10577
+ }
10578
+ /** Leaf-only: not on the recipe interface — only the leaf can read data directly. */
10579
+ getData() {
10580
+ if (this.dataCache === void 0) this.dataCache = { value: this.options.getData() };
10581
+ return this.dataCache.value;
10582
+ }
10583
+ getDataStatus() {
10584
+ if (this.dataStatusCache === void 0) this.dataStatusCache = { value: this.options.getDataStatus() };
10585
+ return this.dataStatusCache.value;
10586
+ }
10587
+ /**
10588
+ * Overlay overrides → produces a {@link ColumnOverriddenRecipe} wrapping
10589
+ * this leaf. ColumnLazy itself stays bare (id remains a plain PObjectId);
10590
+ * layering lives entirely in the recipe wrappers.
10591
+ */
10592
+ withSpecs(overrides) {
10593
+ return ColumnOverriddenRecipe.wrap(this, overrides);
10594
+ }
10595
+ /**
10596
+ * Resolve via the ambient {@link ColumnRegistry}. Spec is resolved eagerly:
10597
+ * returns `undefined` if the leaf isn't reachable yet (resolving). Throws
10598
+ * {@link ColumnAbsentError} when every relevant accessor is `inputsLocked`
10599
+ * and the column did not appear — the column will not exist in this ctx.
10600
+ * Data and dataStatus stay lazy.
10601
+ */
10602
+ static fromId(id, { ctx } = {}) {
10603
+ const registry = new ColumnRegistry(getCtxProviders({ ctx }));
10604
+ const leaf = registry.resolve(id);
10605
+ if (isNil(leaf)) {
10606
+ if (registry.isFinal()) throw new ColumnAbsentError(id);
10607
+ return;
10608
+ }
10609
+ const spec = readSpecAccessor(leaf);
10610
+ if (isNil(spec)) {
10611
+ if (leaf.accessor.getInputsLocked()) throw new ColumnAbsentError(id);
10612
+ return;
10613
+ }
10614
+ if (!spec.hasData()) return void 0;
10615
+ return new ColumnLazyImpl(id, {
10616
+ getSpec: () => spec.getDataAsJson(),
10617
+ getData: () => readDataAccessor(leaf),
10618
+ getDataStatus: () => readDataStatus(leaf)
10619
+ });
10620
+ }
10621
+ /** {@link PlRef} wrapper over {@link fromId}. */
10622
+ static fromPlRef(ref) {
10623
+ return ColumnLazyImpl.fromId(createGlobalPObjectId(ref.blockId, ref.name));
10624
+ }
10625
+ /**
10626
+ * Bind directly to an accessor-backed {@link LeafEntry} — no registry.
10627
+ * Throws {@link ColumnAbsentError} if the leaf has no spec field and its
10628
+ * accessor is `inputsLocked`. Returns `undefined` while still resolving.
10629
+ */
10630
+ static fromAccessor(entry) {
10631
+ const spec = readSpecAccessor(entry);
10632
+ if (isNil(spec)) {
10633
+ if (entry.accessor.getInputsLocked()) throw new ColumnAbsentError(entry.id);
10634
+ return;
10635
+ }
10636
+ if (!spec.hasData()) return void 0;
10637
+ return new ColumnLazyImpl(entry.id, {
10638
+ getSpec: () => spec.getDataAsJson(),
10639
+ getData: () => readDataAccessor(entry),
10640
+ getDataStatus: () => readDataStatus(entry)
10641
+ });
10642
+ }
10643
+ /**
10644
+ * Wrap a materialised {@link PColumn}. If the input is already a
10645
+ * {@link ColumnLazy} it is returned as-is.
10646
+ */
10647
+ static fromColumn(column) {
10648
+ if (column instanceof ColumnLazyImpl) return column;
10649
+ return new ColumnLazyImpl(column.id, {
10650
+ getSpec: () => column.spec,
10651
+ getData: () => column.data,
10652
+ getDataStatus: () => "present"
10653
+ });
10654
+ }
10655
+ /**
10656
+ * Distinguishes `present` / `resolving` / `absent` for a {@link PObjectId}
10657
+ * in the active render ctx. Falls back to the registry's `isFinal()`
10658
+ * when the id has no entry — only then we can say `absent` instead of
10659
+ * `resolving`.
10660
+ */
10661
+ static getStatusById(id, { ctx } = {}) {
10662
+ const registry = new ColumnRegistry(getCtxProviders({ ctx }));
10663
+ const leaf = registry.resolve(id);
10664
+ if (isNil(leaf)) return registry.isFinal() ? "absent" : "resolving";
10665
+ return getLeafEntryStatus(leaf);
10666
+ }
10667
+ /** {@link PlRef} wrapper over {@link getStatusById}. */
10668
+ static getStatusByPlRef(ref, opts = {}) {
10669
+ return ColumnLazyImpl.getStatusById(createGlobalPObjectId(ref.blockId, ref.name), opts);
10670
+ }
10671
+ /** No registry — reads straight off the entry's accessor. */
10672
+ static getStatusByAccessor(entry) {
10673
+ return getLeafEntryStatus(entry);
10674
+ }
10675
+ };
10676
+ /**
10677
+ * Unified dispatcher — picks the right `ColumnLazyImpl.fromX` by source
10678
+ * shape. For ambiguous inputs callers can still use the explicit factories
10679
+ * (also attached as properties: `ColumnLazy.fromId`, `.fromPlRef`,
10680
+ * `.fromAccessor`, `.fromColumn`).
10681
+ */
10682
+ function ColumnLazyDispatch(source, opts = {}) {
10683
+ if (typeof source === "string") return ColumnLazyImpl.fromId(source, opts);
10684
+ if (source instanceof ColumnLazyImpl) return source;
10685
+ if ("accessor" in source) return ColumnLazyImpl.fromAccessor(source);
10686
+ if (isPlRef(source)) return ColumnLazyImpl.fromPlRef(source);
10687
+ if (isPColumn(source)) return ColumnLazyImpl.fromColumn(source);
10688
+ throw new Error("ColumnLazy: unknown source shape");
10689
+ }
10690
+ /**
10691
+ * Polymorphic counterpart to {@link ColumnLazyDispatch}: returns the
10692
+ * {@link ColumnResolutionStatus} for any factory input without constructing
10693
+ * the recipe. For already-materialised sources ({@link PColumn} value,
10694
+ * existing {@link ColumnLazy}) status is `present` by construction.
10695
+ */
10696
+ function ColumnLazyGetStatus(source, opts = {}) {
10697
+ if (typeof source === "string") return ColumnLazyImpl.getStatusById(source, opts);
10698
+ if (source instanceof ColumnLazyImpl) return "present";
10699
+ if ("accessor" in source) return ColumnLazyImpl.getStatusByAccessor(source);
10700
+ if (isPlRef(source)) return ColumnLazyImpl.getStatusByPlRef(source, opts);
10701
+ if (isPColumn(source)) return "present";
10702
+ throw new Error("ColumnLazy.getStatus: unknown source shape");
10703
+ }
10704
+ const ColumnLazy = Object.assign(ColumnLazyDispatch, {
10705
+ fromId: ColumnLazyImpl.fromId,
10706
+ fromPlRef: ColumnLazyImpl.fromPlRef,
10707
+ fromAccessor: ColumnLazyImpl.fromAccessor,
10708
+ fromColumn: ColumnLazyImpl.fromColumn,
10709
+ getStatus: ColumnLazyGetStatus,
10710
+ getStatusById: ColumnLazyImpl.getStatusById,
10711
+ getStatusByPlRef: ColumnLazyImpl.getStatusByPlRef,
10712
+ getStatusByAccessor: ColumnLazyImpl.getStatusByAccessor
10713
+ });
10714
+ const readSpecAccessor = memoizeByEntry(({ accessor, name }) => accessor.traverse({
10715
+ field: `${name}.spec`,
10716
+ assertFieldType: "Input",
10717
+ ignoreError: true
10718
+ }));
10719
+ /**
10720
+ * Per-entry counterpart to {@link readDataStatus}: tells whether the leaf's
10721
+ * **spec** can be read in this ctx, and — for the negative cases —
10722
+ * distinguishes `resolving` from `absent` via `getInputsLocked()`.
10723
+ *
10724
+ * - spec field not yet on the entry's accessor + inputs locked → `absent`
10725
+ * - spec field not yet on the entry's accessor + still resolving → `resolving`
10726
+ * - spec resource present but bytes not yet written → `resolving`
10727
+ * (transient — the spec resource is connected, just unfilled)
10728
+ * - spec resource present and `hasData()` → `present`
10729
+ */
10730
+ function getLeafEntryStatus(entry) {
10731
+ const spec = readSpecAccessor(entry);
10732
+ if (isNil(spec)) return entry.accessor.getInputsLocked() ? "absent" : "resolving";
10733
+ if (!spec.hasData()) return "resolving";
10734
+ return "present";
10735
+ }
10736
+ const readDataAccessor = memoizeByEntry(({ accessor, name }) => accessor.traverse({
10737
+ field: `${name}.data`,
10738
+ assertFieldType: "Input",
10739
+ ignoreError: true
10740
+ }));
10741
+ const readDataStatus = memoizeByEntry(({ accessor, name }) => {
10742
+ if (accessor.listInputFields().includes(`${name}.data`)) return "present";
10743
+ return accessor.getInputsLocked() ? "absent" : "resolving";
10744
+ });
10745
+ function memoizeByEntry(fn) {
10746
+ const cache = new LRUCache({ max: 1e3 });
10747
+ return (entry) => {
10748
+ const key = `${entry.accessor.handle}:${entry.name}`;
10749
+ let hit = cache.get(key);
10750
+ if (!hit) cache.set(key, hit = { value: fn(entry) });
10751
+ return hit.value;
10752
+ };
10753
+ }
10754
+ //#endregion
10755
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column_recipes/index.js
10756
+ /**
10757
+ * Build a `ColumnRecipe` from a stringified id. Dispatches to the matching
10758
+ * concrete recipe variant based on the id's encoding and recurses on
10759
+ * wrappers' inner `source`:
10760
+ *
10761
+ * - bare {@link PObjectId} (non-JSON) → `ColumnLazy.fromId`
10762
+ * - `ColumnDiscoveredKey` → {@link ColumnDiscoveredRecipe}
10763
+ * - `ColumnOverriddenKey { source, specOverrides }` → recurse on `source`,
10764
+ * then {@link ColumnOverriddenRecipe.wrap}
10765
+ * - `ColumnFilteredKey { source, axisFilters }` → recurse on `source`,
10766
+ * then {@link ColumnFilteredRecipe.wrap}
10767
+ *
10768
+ * Returns `undefined` for unsupported variants (e.g. AnchoredPColumnId,
10769
+ * which needs an anchor map to resolve) or when a nested source itself
10770
+ * cannot be built.
10771
+ */
10772
+ function ColumnRecipeBuild(id, opts = {}) {
10773
+ const parsed = parseColumnIdSafely(id);
10774
+ if (isPObjectKey(parsed)) return ColumnLazyImpl.fromId(id, opts);
10775
+ if (isColumnDiscoveredKey(parsed)) return ColumnDiscoveredRecipe.fromKey(parsed, opts);
10776
+ if (isColumnOverriddenKey(parsed)) {
10777
+ const inner = ColumnRecipe(parsed.source, opts);
10778
+ if (inner === void 0) return void 0;
10779
+ return ColumnOverriddenRecipe.wrap(inner, parsed.specOverrides);
10780
+ }
10781
+ if (isColumnFilteredKey(parsed)) {
10782
+ if (typeof parsed.source !== "string") throw new Error(`Unsupported ColumnRecipe id variant: filtered column with non-string source (${JSON.stringify(parsed.source)})`);
10783
+ const inner = ColumnRecipe(parsed.source, opts);
10784
+ if (inner === void 0) return void 0;
10785
+ return ColumnFilteredRecipe.wrap(inner, parsed.axisFilters);
10786
+ }
10787
+ throw new Error(`Unsupported ColumnRecipe id variant: ${id}`);
10788
+ }
10789
+ /**
10790
+ * Resolution status counterpart to {@link ColumnRecipeBuild}. Dispatches on
10791
+ * the parsed id shape to the matching `getStatusBy*` static — never
10792
+ * constructs the recipe. Use this at boundaries (resolver, filter/sort
10793
+ * targets) to throw early on `absent` instead of silently producing an empty
10794
+ * recipe via {@link ColumnRecipeBuild}.
10795
+ */
10796
+ function ColumnRecipeGetStatus(id, opts = {}) {
10797
+ const parsed = parseColumnIdSafely(id);
10798
+ if (isPObjectKey(parsed)) return ColumnLazyImpl.getStatusById(id, opts);
10799
+ if (isColumnDiscoveredKey(parsed)) return ColumnDiscoveredRecipe.getStatusByKey(parsed, opts);
10800
+ if (isColumnOverriddenKey(parsed)) return ColumnOverriddenRecipe.getStatusByKey(parsed, opts);
10801
+ if (isColumnFilteredKey(parsed)) return ColumnFilteredRecipe.getStatusByKey(parsed, opts);
10802
+ throw new Error(`Unsupported ColumnRecipe id variant: ${id}`);
10803
+ }
10804
+ const ColumnRecipe = Object.assign(ColumnRecipeBuild, { getStatus: ColumnRecipeGetStatus });
10805
+ //#endregion
10806
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/column.js
10807
+ /**
10808
+ * Unified entry point — routes between the two top-level dispatchers:
10809
+ * - string id (`PObjectId` / `ColumnUniversalId`) → {@link ColumnRecipe}
10810
+ * - object source (`PlRef` / `LeafEntry` / `PColumn` / `ColumnLazy`) → {@link ColumnLazy}
10811
+ *
10812
+ * `ColumnLazy` is itself a `ColumnRecipe<PObjectId>`, so the return type is
10813
+ * the common `ColumnRecipe`.
10814
+ */
10815
+ function Column(source, opts) {
10816
+ if (typeof source === "string") return ColumnRecipe(source, opts);
10817
+ return ColumnLazy(source, opts);
10818
+ }
10819
+ //#endregion
10820
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/columns_collection.js
10821
+ /**
10822
+ * Build a {@link ColumnsCollection} from sandbox-side source descriptors.
10823
+ * Resolves the `columnsCollection` driver (either from `deps.driver` or via
10824
+ * `getService("columnsCollection")`) and asks the host to mint a fresh
10825
+ * handle covering the supplied sources. Pass `sources === undefined` to
10826
+ * fall back to the active render ctx (main outputs + prerun + result pool).
10827
+ *
10828
+ * `sources` accepts {@link ColumnsSourceShorthand} string literals
10829
+ * (`"result_pool"`, `"current_block"`) for the common ctx-derived sources.
10830
+ */
10831
+ function ColumnsCollection(sources, deps) {
10832
+ const driver = deps?.driver ?? getService("columnsCollection", { ctx: deps?.ctx });
10833
+ const serialized = sources ? sources.flatMap((s) => toSerializedSources(s, deps?.ctx)) : defaultCtxSources(deps?.ctx);
10834
+ return new ColumnsCollectionImpl(driver.create(serialized), driver);
10835
+ }
10836
+ /**
10837
+ * Sandbox proxy over the host-side `ColumnsCollection` driver. The driver
10838
+ * owns all column-set state; this object only carries an opaque
10839
+ * {@link CollectionHandle} plus a reference to the driver service.
10840
+ *
10841
+ * Construct via {@link ColumnsCollection} — the bare constructor is a
10842
+ * trivial `(handle, driver)` pair so that `addSource` / `discover` / `filter`
10843
+ * can rebind a freshly-minted handle without going through source
10844
+ * serialisation again.
10845
+ *
10846
+ * Every method returning a `ColumnsCollection` mints a fresh handle on the
10847
+ * host — the host VM bridge pins it to the active render ctx, so the sandbox
10848
+ * never has to manage refcounts.
10849
+ */
10850
+ var ColumnsCollectionImpl = class ColumnsCollectionImpl {
10851
+ handle;
10852
+ driver;
10853
+ constructor(handle, driver) {
10854
+ this.handle = handle;
10855
+ this.driver = driver;
10856
+ }
10857
+ isEmpty() {
10858
+ return this.driver.isEmpty(this.handle);
10859
+ }
10860
+ isFinal() {
10861
+ return this.driver.isFinal(this.handle);
10862
+ }
10863
+ getColumnIds() {
10864
+ return this.driver.getColumns(this.handle);
10865
+ }
10866
+ getColumns() {
10867
+ return this.getColumnIds().map((id) => ColumnRecipe(id)).filter((c) => !isNil(c));
10868
+ }
10869
+ addSource(source) {
10870
+ return new ColumnsCollectionImpl(this.driver.addSource(this.handle, toSerializedSources(source)), this.driver);
10871
+ }
10872
+ discover(options) {
10873
+ return new ColumnsCollectionImpl(this.driver.discover(this.handle, options), this.driver);
10874
+ }
10875
+ filter(options) {
10876
+ return new ColumnsCollectionImpl(this.driver.filter(this.handle, options), this.driver);
10877
+ }
10878
+ };
10879
+ function toSerializedSources(source, ctx) {
10880
+ if (source === "result_pool") return [{ kind: "result_pool" }];
10881
+ if (source === "current_block") return currentBlockSources(ctx);
10882
+ if (source instanceof ColumnsCollectionImpl) return [{
10883
+ kind: "collection",
10884
+ handle: source.handle
10885
+ }];
10886
+ if (source instanceof TreeNodeAccessor) return [{
10887
+ kind: "accessor",
10888
+ accessor: source.handle,
10889
+ path: source.resolvePath
10890
+ }];
10891
+ if (isColumnArray(source)) return [{
10892
+ kind: "ids",
10893
+ ids: source.columns.map((c) => c.id),
10894
+ isFinal: source.isFinal
10895
+ }];
10896
+ if (isColumnProvider(source)) return [{
10897
+ kind: "ids",
10898
+ ids: source.getColumns().map((c) => c.id),
10899
+ isFinal: source.isFinal()
10900
+ }];
10901
+ throw new Error("ColumnsCollection: unrecognised ColumnsSource shape");
10902
+ }
10903
+ function isColumnArray(source) {
10904
+ if (typeof source !== "object" || source === null) return false;
10905
+ const s = source;
10906
+ return Array.isArray(s.columns) && typeof s.isFinal === "boolean";
10907
+ }
10908
+ function currentBlockSources(ctx) {
10909
+ const renderCtx = ctx ?? getCfgRenderCtx();
10910
+ const sources = [];
10911
+ const outputs = renderCtx.getAccessorHandleByName(MainAccessorName);
10912
+ if (outputs !== void 0) sources.push({
10913
+ kind: "accessor",
10914
+ accessor: outputs,
10915
+ path: [MainAccessorName]
10916
+ });
10917
+ const prerun = renderCtx.getAccessorHandleByName(StagingAccessorName);
10918
+ if (prerun !== void 0) sources.push({
10919
+ kind: "accessor",
10920
+ accessor: prerun,
10921
+ path: [StagingAccessorName]
10922
+ });
10923
+ return sources;
10924
+ }
10925
+ function defaultCtxSources(ctx) {
10926
+ return [...currentBlockSources(ctx), { kind: "result_pool" }];
10927
+ }
10928
+ //#endregion
10929
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/columns/utils.js
10930
+ /**
10931
+ * PObjectIds of every non-hit column referenced by `recipe.getQuery()`,
10932
+ * deduped in traversal order. The hit column is
10933
+ * `extractPObjectId(recipe.id)`; anything else in the query is a linker or
10934
+ * other engine-consumed column.
10935
+ *
10936
+ * Pure query walk — no registry access. Use {@link collectLinkerColumns} for
10937
+ * the resolved {@link ColumnLazy} variant.
10938
+ */
10939
+ function collectLinkerIds(recipe) {
10940
+ const hit = extractPObjectId(recipe.id);
10941
+ const seen = /* @__PURE__ */ new Set();
10942
+ const out = [];
10943
+ for (const id of collectSpecQueryColumns(recipe.getQuery())) {
10944
+ const bare = extractPObjectId(id);
10945
+ if (bare === hit) continue;
10946
+ if (seen.has(bare)) continue;
10947
+ seen.add(bare);
10948
+ out.push(bare);
10949
+ }
10950
+ return out;
10951
+ }
10952
+ /**
10953
+ * {@link collectLinkerIds} resolved against the ambient context as
10954
+ * {@link ColumnLazy} instances. Throws if any id fails to resolve —
10955
+ * matches the contract of the legacy `resolveLinkers` it replaces.
10956
+ */
10957
+ function collectLinkerColumns(recipe, opts = {}) {
10958
+ return collectLinkerIds(recipe).map((id) => ColumnLazyImpl.fromId(id, opts) ?? throwError(`materializeLinkers: linker ${id} not resolvable`));
10959
+ }
10960
+ /**
10961
+ * Hit-side axis qualifications for the recipe — the ones that should land on
10962
+ * the outer-join entry wrapping this column at the consumer boundary.
10963
+ *
10964
+ * Descends {@link ColumnOverriddenRecipe} / {@link ColumnFilteredRecipe} via
10965
+ * `getInner()` until it finds a {@link ColumnDiscoveredRecipe}; otherwise
10966
+ * returns `[]`. Pure recipe walk — no query-tree introspection.
10967
+ */
10968
+ function hitQualifications(recipe) {
10969
+ return findDiscovered(recipe)?.getColumnQualifications() ?? [];
10970
+ }
10971
+ /**
10972
+ * Per-primary-column axis qualifications for the recipe — applied to the
10973
+ * outer primary anchors on this recipe's group side. Keyed by the external
10974
+ * primary column id (NOT by columns inside this recipe's own query).
10975
+ *
10976
+ * Same walk strategy as {@link hitQualifications}.
10977
+ */
10978
+ function queriesQualifications(recipe) {
10979
+ return findDiscovered(recipe)?.getQueriesQualifications() ?? {};
10980
+ }
10981
+ /**
10982
+ * Whether the recipe's underlying data resources actually carry bytes —
10983
+ * strictly stronger than `getDataStatus() === "present"`, which only tells
10984
+ * that the `.data` field is wired onto the accessor.
10985
+ *
10986
+ * Walks every physical leaf the recipe depends on via
10987
+ * {@link ColumnRecipe.getReferencedIds} (resolves each id back to a
10988
+ * {@link ColumnLazy} through the ambient ctx) and ANDs `hasData()` across
10989
+ * all of them. Inline {@link PColumnValues} payloads count as present.
10990
+ *
10991
+ * Returns `false` if any leaf cannot be re-resolved in `opts.ctx` (treat as
10992
+ * "not yet ready") rather than throwing — this is a UI-facing predicate, not
10993
+ * a contract assertion.
10994
+ */
10995
+ function hasColumnData(recipe, opts = {}) {
10996
+ for (const id of recipe.getReferencedIds()) {
10997
+ const lazy = ColumnLazyImpl.fromId(id, opts);
10998
+ if (lazy === void 0) return false;
10999
+ if (lazy.getDataStatus() !== "present") return false;
11000
+ if (!isLazyDataPresent(lazy.getData())) return false;
11001
+ }
11002
+ return true;
11003
+ }
11004
+ function isLazyDataPresent(data) {
11005
+ if (data === void 0) return false;
11006
+ if (Array.isArray(data)) return true;
11007
+ if (data instanceof TreeNodeAccessor) return data.hasData();
11008
+ if (isDataInfo(data)) {
11009
+ let ok = true;
11010
+ visitDataInfo(data, (blob) => {
11011
+ ok &&= blob.hasData();
11012
+ });
11013
+ return ok;
11014
+ }
11015
+ return false;
11016
+ }
11017
+ /**
11018
+ * Walk wrapper layers (Overridden, Filtered) until a {@link
11019
+ * ColumnDiscoveredRecipe} is found. Returns `undefined` if the recipe chain
11020
+ * has no Discovered layer (bare leaves and Overridden-over-leaf cases).
11021
+ *
11022
+ * Invariant from the wrapper classes themselves: there is at most one
11023
+ * Discovered layer in any recipe chain — Discovered is constructed only via
11024
+ * its own factory and is never re-wrapped by Discovered.
11025
+ */
11026
+ function findDiscovered(recipe) {
11027
+ let current = recipe;
11028
+ while (true) {
11029
+ if (current instanceof ColumnDiscoveredRecipe) return current;
11030
+ if (current instanceof ColumnOverriddenRecipe || current instanceof ColumnFilteredRecipe) {
11031
+ current = current.getInner();
11032
+ continue;
8160
11033
  }
8161
- const allOutputs = {
8162
- ...this.config.outputs,
8163
- ...pluginOutputs
8164
- };
8165
- globalThis.platformaApiVersion = apiVersion;
8166
- if (!isInUI()) return { config: {
8167
- v4: {
8168
- configVersion: 4,
8169
- modelAPIVersion: 2,
8170
- sdkVersion: PlatformaSDKVersion,
8171
- renderingMode: this.config.renderingMode,
8172
- sections: this.config.sections,
8173
- title: this.config.title,
8174
- subtitle: this.config.subtitle,
8175
- tags: this.config.tags,
8176
- outputs: allOutputs,
8177
- enrichmentTargets: this.config.enrichmentTargets,
8178
- featureFlags: this.config.featureFlags,
8179
- blockLifecycleCallbacks: { ...BlockStorageFacadeHandles }
8180
- },
8181
- sdkVersion: PlatformaSDKVersion,
8182
- renderingMode: this.config.renderingMode,
8183
- sections: this.config.sections,
8184
- outputs: Object.fromEntries(Object.entries(this.config.outputs).map(([key, value]) => [key, downgradeCfgOrLambda(value)]))
8185
- } };
8186
- else return {
8187
- ...getPlatformaInstance({
8188
- sdkVersion: PlatformaSDKVersion,
8189
- apiVersion
8190
- }),
8191
- blockModelInfo: {
8192
- outputs: Object.fromEntries(Object.entries(allOutputs).map(([key, value]) => [key, { withStatus: Boolean(isConfigLambda(value) && value.withStatus) }])),
8193
- pluginIds: pluginHandles,
8194
- featureFlags: this.config.featureFlags,
8195
- pluginPublicOutputs: Object.fromEntries(pluginHandles.map((handle) => [handle, plugins[handle].model.publicOutputDef]))
8196
- }
8197
- };
11034
+ return;
8198
11035
  }
8199
- };
11036
+ }
11037
+ /**
11038
+ * A recipe is a "leaf" (directly co-indexed on the anchor, reached without a
11039
+ * linker chain) iff its wrapper chain contains no {@link ColumnDiscoveredRecipe}.
11040
+ *
11041
+ * `Filtered` / `Overridden` over a bare leaf stay leaves; anything wrapping a
11042
+ * `Discovered` (e.g. `Overridden(Discovered(...))`) is linked. Use this — not an
11043
+ * `instanceof ColumnLazyImpl` check — to split direct vs. linker-joined columns,
11044
+ * since projections over a plain leaf are still direct.
11045
+ */
11046
+ function isLeafColumn(recipe) {
11047
+ return findDiscovered(recipe) === void 0;
11048
+ }
8200
11049
  //#endregion
8201
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/filters/traverse.js
11050
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/filters/traverse.js
8202
11051
  /**
8203
11052
  * Recursively traverses a FilterSpec tree bottom-up, applying visitor callbacks.
8204
11053
  *
@@ -8237,16 +11086,15 @@ function collectFilterSpecColumns(filter) {
8237
11086
  });
8238
11087
  }
8239
11088
  //#endregion
8240
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/filters/converters/filterToQuery.js
8241
- /** Parses a CanonicalizedJson<PTableColumnId> string into a SpecQueryExpression reference. */
8242
- function resolveColumnRef(columnStr) {
8243
- const parsed = JSON.parse(columnStr);
8244
- return parsed.type === "axis" ? {
11089
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/filters/converters/filterToQuery.js
11090
+ /** Converts a QueryColumnId object into a SpecQueryExpression reference. */
11091
+ function resolveColumnRef(col) {
11092
+ return col.type === "axis" ? {
8245
11093
  type: "axisRef",
8246
- value: parsed.id
11094
+ value: col.id
8247
11095
  } : {
8248
11096
  type: "columnRef",
8249
- value: parsed.id
11097
+ value: col.id
8250
11098
  };
8251
11099
  }
8252
11100
  /** Converts a FilterSpec tree into a SpecQueryExpression. */
@@ -8566,7 +11414,7 @@ function isEmpty(value) {
8566
11414
  return true;
8567
11415
  }
8568
11416
  //#endregion
8569
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/filters/distill.js
11417
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/filters/distill.js
8570
11418
  /**
8571
11419
  * Strips non-FilterSpec metadata (whitelist approach) and removes
8572
11420
  * unfilled leaves (type is undefined or any required field is undefined).
@@ -8671,7 +11519,7 @@ const REQUIRED_KEYS_BY_TYPE = {
8671
11519
  greaterThanColumnOrEqual: ["column", "rhs"]
8672
11520
  };
8673
11521
  //#endregion
8674
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/components/PlDataTable/state-migration.js
11522
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/components/PlDataTable/state-migration.js
8675
11523
  /** Upgrade PlDataTableStateV2 to the latest version */
8676
11524
  function upgradePlDataTableStateV2(state) {
8677
11525
  if (!state) return createPlDataTableStateV2();
@@ -8682,12 +11530,13 @@ function upgradePlDataTableStateV2(state) {
8682
11530
  ...entry,
8683
11531
  filtersState: []
8684
11532
  })),
8685
- pTableParams: createDefaultPTableParams()
11533
+ pTableParams: createDefaultPTableParamsV7()
8686
11534
  };
8687
11535
  if (state.version === 3) state = createPlDataTableStateV2();
8688
11536
  if (state.version === 4) state = migrateV4toV6(state);
8689
11537
  if (state.version === 5) state = migrateV5toV6(state);
8690
11538
  if (state.version === 6) state = migrateV6toV7(state);
11539
+ if (state.version === 7) state = migrateV7toV8(state);
8691
11540
  return state;
8692
11541
  }
8693
11542
  /** Migrate v5 to v6: unwrap `{source, labeled}` colIds in gridState. */
@@ -8698,7 +11547,7 @@ function migrateV5toV6(state) {
8698
11547
  ...entry,
8699
11548
  gridState: unwrapV5GridState(entry.gridState)
8700
11549
  })),
8701
- pTableParams: createDefaultPTableParams()
11550
+ pTableParams: createDefaultPTableParamsV7()
8702
11551
  };
8703
11552
  }
8704
11553
  /** Convert v5 wrapped colId JSON to bare PTableColumnSpec JSON, taking `.source`.
@@ -8755,10 +11604,7 @@ function migrateV4toV6(state) {
8755
11604
  const nextId = () => ++idCounter;
8756
11605
  const migratedCache = state.stateCache.map((entry) => {
8757
11606
  const leaves = [];
8758
- for (const f of entry.filtersState) if (f.filter !== null && !f.filter.disabled) {
8759
- const column = canonicalizeJson(f.id);
8760
- leaves.push(migrateTableFilter(column, f.filter.value, nextId));
8761
- }
11607
+ for (const f of entry.filtersState) if (f.filter !== null && !f.filter.disabled) leaves.push(migrateTableFilter(canonicalizeJson(f.id), f.filter.value, nextId));
8762
11608
  const filtersState = leaves.length > 0 ? {
8763
11609
  id: nextId(),
8764
11610
  type: "and",
@@ -8786,10 +11632,11 @@ function migrateV4toV6(state) {
8786
11632
  filters: distillFilterSpec(currentCache.filtersState),
8787
11633
  defaultFilters: null,
8788
11634
  sorting: state.pTableParams.sorting
8789
- } : createDefaultPTableParams()
11635
+ } : createDefaultPTableParamsV7()
8790
11636
  };
8791
11637
  }
8792
- /** Migrate a single per-column PlTableFilter to a tree-based FilterSpec node */
11638
+ /** Migrate a single per-column PlTableFilter to a v7-form tree node (legacy
11639
+ * string column ids). v7 → v8 later converts these to object form. */
8793
11640
  function migrateTableFilter(column, filter, nextId) {
8794
11641
  const id = nextId();
8795
11642
  switch (filter.type) {
@@ -8915,7 +11762,9 @@ function migrateTableFilter(column, filter, nextId) {
8915
11762
  };
8916
11763
  }
8917
11764
  }
8918
- function createDefaultPTableParams() {
11765
+ /** Default pTableParams in the v7 shape (sorting: []). Used by intermediate
11766
+ * migration steps that produce v6/v7 state before the v7 → v8 conversion. */
11767
+ function createDefaultPTableParamsV7() {
8919
11768
  return {
8920
11769
  sourceId: null,
8921
11770
  hiddenColIds: null,
@@ -8924,87 +11773,232 @@ function createDefaultPTableParams() {
8924
11773
  sorting: []
8925
11774
  };
8926
11775
  }
11776
+ function createDefaultPTableParams() {
11777
+ return {
11778
+ sourceId: null,
11779
+ hiddenColIds: null,
11780
+ filters: null,
11781
+ defaultFilters: null,
11782
+ sorting: null
11783
+ };
11784
+ }
8927
11785
  function createPlDataTableStateV2() {
8928
11786
  return {
8929
- version: 7,
11787
+ version: 8,
8930
11788
  stateCache: [],
8931
11789
  pTableParams: createDefaultPTableParams()
8932
11790
  };
8933
11791
  }
11792
+ function migrateV7toV8(state) {
11793
+ const newCache = state.stateCache.map((entry) => ({
11794
+ sourceId: entry.sourceId,
11795
+ gridState: entry.gridState,
11796
+ sheetsState: entry.sheetsState,
11797
+ filtersState: convertFiltersWithMeta(entry.filtersState),
11798
+ defaultFiltersState: convertFiltersWithMeta(entry.defaultFiltersState),
11799
+ searchString: entry.searchString
11800
+ }));
11801
+ const params = state.pTableParams;
11802
+ let pTableParams;
11803
+ if (params.sourceId === null) pTableParams = createDefaultPTableParams();
11804
+ else pTableParams = {
11805
+ sourceId: params.sourceId,
11806
+ hiddenColIds: params.hiddenColIds,
11807
+ sorting: params.sorting.length === 0 ? null : params.sorting,
11808
+ filters: convertFiltersPlain(params.filters),
11809
+ defaultFilters: convertFiltersPlain(params.defaultFilters)
11810
+ };
11811
+ return {
11812
+ version: 8,
11813
+ stateCache: newCache,
11814
+ pTableParams
11815
+ };
11816
+ }
11817
+ function convertFiltersWithMeta(node) {
11818
+ if (node === null) return null;
11819
+ const result = pruneFilterNode(node);
11820
+ if (result === void 0) return null;
11821
+ return result;
11822
+ }
11823
+ function convertFiltersPlain(node) {
11824
+ if (node === null) return null;
11825
+ const result = pruneFilterNode(node);
11826
+ if (result === void 0) return null;
11827
+ return result;
11828
+ }
11829
+ /** Recursively converts and prunes a legacy v7 filter tree. Preserves meta
11830
+ * fields (id/isExpanded/source/isSuppressed) on non-leaf nodes. Returns
11831
+ * `undefined` when the subtree is empty after pruning. */
11832
+ function pruneFilterNode(node) {
11833
+ if (!node || typeof node !== "object") return void 0;
11834
+ const n = node;
11835
+ if (n.type === "and" || n.type === "or") {
11836
+ const kept = (n.filters ?? []).map((f) => pruneFilterNode(f)).filter((f) => f !== void 0);
11837
+ if (kept.length === 0) return void 0;
11838
+ return {
11839
+ ...n,
11840
+ type: n.type,
11841
+ filters: kept
11842
+ };
11843
+ }
11844
+ if (n.type === "not") {
11845
+ const inner = pruneFilterNode(n.filter);
11846
+ if (inner === void 0) return void 0;
11847
+ return {
11848
+ ...n,
11849
+ type: "not",
11850
+ filter: inner
11851
+ };
11852
+ }
11853
+ return convertLegacyLeaf(n);
11854
+ }
11855
+ function convertLegacyLeaf(leaf) {
11856
+ if (leaf.type === void 0) return leaf;
11857
+ const result = { ...leaf };
11858
+ if ("column" in result) {
11859
+ const c = parseLegacyLeafColumn(result.column);
11860
+ if (c === void 0) return void 0;
11861
+ result.column = c;
11862
+ }
11863
+ if ("rhs" in result) {
11864
+ const c = parseLegacyLeafColumn(result.rhs);
11865
+ if (c === void 0) return void 0;
11866
+ result.rhs = c;
11867
+ }
11868
+ return result;
11869
+ }
11870
+ function parseLegacyLeafColumn(s) {
11871
+ if (typeof s !== "string") return void 0;
11872
+ const parsed = parseJsonSafely(s);
11873
+ if (!parsed || typeof parsed !== "object") return void 0;
11874
+ if (!("type" in parsed) || !("id" in parsed)) return void 0;
11875
+ const t = parsed.type;
11876
+ if (t !== "axis" && t !== "column") return void 0;
11877
+ return parsed;
11878
+ }
8934
11879
  //#endregion
8935
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/components/PlDataTable/createPlDataTable/utils.js
11880
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/components/PlDataTable/createPlDataTable/utils.js
11881
+ /** Adapt a {@link ColumnRecipe} to the plain {@link RuleColumn} shape. */
11882
+ function toRuleColumn(col) {
11883
+ return {
11884
+ id: extractPObjectId(col.id),
11885
+ spec: col.getSpec()
11886
+ };
11887
+ }
11888
+ /** Check if column should be omitted from the table */
11889
+ function isColumnHidden(spec) {
11890
+ return readAnnotation(spec, Annotation.Table.Visibility) === "hidden";
11891
+ }
8936
11892
  /** Check if column is hidden by default */
8937
11893
  function isColumnOptional(spec) {
8938
11894
  return readAnnotation(spec, Annotation.Table.Visibility) === "optional";
8939
11895
  }
8940
- //#endregion
8941
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/components/PlDataTable/labels.js
8942
- /** Get label columns matching the provided columns from the result pool */
8943
- function getMatchingLabelColumns(columns, allLabelColumns) {
8944
- const inputLabelColumns = [];
8945
- const inputValueColumns = [];
8946
- for (const column of columns) if (isLabelColumn(column.spec)) inputLabelColumns.push(column);
8947
- else inputValueColumns.push(column);
8948
- const unlabeledAxes = [];
8949
- for (const column of inputValueColumns) for (const axis of column.spec.axesSpec) {
8950
- const axisId = getAxisId(axis);
8951
- if (!unlabeledAxes.some((id) => matchAxisId(id, axisId))) unlabeledAxes.push(axisId);
8952
- }
8953
- for (const labelColumn of inputLabelColumns) {
8954
- const labelAxisId = getAxisId(labelColumn.spec.axesSpec[0]);
8955
- const labelMatch = unlabeledAxes.findIndex((axisId) => matchAxisId(axisId, labelAxisId));
8956
- if (labelMatch !== -1) unlabeledAxes.splice(labelMatch, 1);
8957
- }
8958
- const colId = (id, domain, contextDomain) => {
8959
- let wid = id.toString();
8960
- if (domain) for (const k in domain) {
8961
- wid += k;
8962
- wid += domain[k];
8963
- }
8964
- if (contextDomain) for (const k in contextDomain) {
8965
- wid += k;
8966
- wid += contextDomain[k];
8967
- }
8968
- return wid;
8969
- };
8970
- const labelColumns = [];
8971
- for (const labelColumn of allLabelColumns) {
8972
- const labelAxis = labelColumn.spec.axesSpec[0];
8973
- const labelAxisId = getAxisId(labelAxis);
8974
- const labelMatch = unlabeledAxes.findIndex((axisId) => matchAxisId(axisId, labelAxisId));
8975
- if (labelMatch !== -1) {
8976
- const axisId = unlabeledAxes[labelMatch];
8977
- if (Object.keys(axisId.domain ?? {}).length + Object.keys(axisId.contextDomain ?? {}).length > Object.keys(labelAxis.domain ?? {}).length + Object.keys(labelAxis.contextDomain ?? {}).length) labelColumns.push({
8978
- id: colId(labelColumn.id, axisId.domain, axisId.contextDomain),
8979
- spec: {
8980
- ...labelColumn.spec,
8981
- axesSpec: [{
8982
- ...axisId,
8983
- annotations: labelAxis.annotations
8984
- }]
8985
- },
8986
- data: labelColumn.data
8987
- });
8988
- else labelColumns.push(labelColumn);
8989
- unlabeledAxes.splice(labelMatch, 1);
11896
+ /** Get effective visibility for a column. Rule map lookup first, then annotation fallback. */
11897
+ function getEffectiveVisibility(col, visibilityByColId) {
11898
+ const rule = visibilityByColId?.get(col.id);
11899
+ if (rule !== void 0) return rule.visibility;
11900
+ if (isColumnHidden(col.spec)) return "hidden";
11901
+ if (isColumnOptional(col.spec)) return "optional";
11902
+ }
11903
+ /** Get ordering priority for a column. Rule map lookup first, then annotation fallback. */
11904
+ function getOrderPriority(col, orderByColId) {
11905
+ const rule = orderByColId?.get(col.id);
11906
+ if (rule !== void 0) return rule.priority;
11907
+ const annotation = Number(readAnnotation(col.spec, Annotation.Table.OrderPriority));
11908
+ return isNaN(annotation) ? void 0 : annotation;
11909
+ }
11910
+ /**
11911
+ * Evaluate display rules against a set of columns and return a map of `colId → winning rule`
11912
+ * (first-match-wins, preserving original rule order).
11913
+ *
11914
+ * Predicate-based rules (`ColumnMatcher`) are evaluated directly on the spec.
11915
+ * Selector-based rules (`ColumnSelector`) are matched via the
11916
+ * `columnsCollection` service — the inline column ids must be resolvable in
11917
+ * the active render ctx for the host to read their specs.
11918
+ */
11919
+ function evaluateRules(rules, columns) {
11920
+ const result = /* @__PURE__ */ new Map();
11921
+ if (rules.length === 0 || columns.length === 0) return result;
11922
+ const selectorRules = rules.filter((rule) => typeof rule.match !== "function");
11923
+ const selectorHitsByRule = /* @__PURE__ */ new Map();
11924
+ if (selectorRules.length > 0) {
11925
+ const baseCollection = ColumnsCollection([{
11926
+ columns: uniqBy(columns, (col) => col.id),
11927
+ isFinal: true
11928
+ }]);
11929
+ for (const rule of selectorRules) {
11930
+ const hitIds = baseCollection.filter({ include: rule.match }).getColumnIds();
11931
+ if (hitIds.length === 0) return result;
11932
+ selectorHitsByRule.set(rule, new Set(hitIds.map((id) => extractPObjectId(id))));
11933
+ }
11934
+ }
11935
+ for (const col of columns) {
11936
+ const colKey = extractPObjectId(col.id);
11937
+ for (const rule of rules) if (selectorHitsByRule.get(rule)?.has(colKey) ?? false) {
11938
+ result.set(colKey, rule);
11939
+ break;
8990
11940
  }
8991
11941
  }
8992
- return labelColumns;
11942
+ return result;
11943
+ }
11944
+ /**
11945
+ * Build a sidecar map `columnId → AnnotationDataStatus` derived from each
11946
+ * recipe's own status. This is *rendering* metadata — kept out of the spec
11947
+ * so it cannot perturb column identity (id-bearing spec overrides would
11948
+ * diverge the visible PTable's column ids from the full table / pframe).
11949
+ *
11950
+ * Mapping `ColumnFieldStatus` × actual byte-presence → `AnnotationDataStatus`:
11951
+ * - `absent` → `"absent"`
11952
+ * - `resolving` → `"computing"`
11953
+ * - `present` + `hasColumnData()` → `"ready"`
11954
+ * - `present` + no bytes yet → `"computing"`
11955
+ *
11956
+ * Intentionally scoped to visible columns — the probe is meaningful only for
11957
+ * what the user will actually see.
11958
+ */
11959
+ function buildDataStatusMap(columns, opts = {}) {
11960
+ return columns.reduce((acc, c) => (acc[c.id] = deriveDataStatus(c, opts), acc), {});
11961
+ }
11962
+ function deriveDataStatus(column, opts) {
11963
+ const field = column.getDataStatus();
11964
+ if (field === "absent") return "absent";
11965
+ if (field === "resolving") return "computing";
11966
+ return hasColumnData(column, opts) ? "ready" : "computing";
11967
+ }
11968
+ /** Derive labels for all table elements: columns via deriveDistinctLabels, axes from label columns. */
11969
+ function deriveAllLabels(options) {
11970
+ const { columns, deriveLabelsOptions } = options;
11971
+ return deriveDistinctLabels(columns.map((c) => ({
11972
+ spec: c.spec,
11973
+ linkerPath: c.linkerPath?.map((step) => ({ spec: step.linker.spec })),
11974
+ qualifications: c.qualifications
11975
+ })), deriveLabelsOptions).reduce((acc, label, index) => (acc[columns[index].id] = label, acc), {});
8993
11976
  }
8994
11977
  //#endregion
8995
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/components/PlDataTable/createPlDataTable/createPTableDefV3.js
11978
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/components/PlDataTable/createPlDataTable/createPTableDefV3.js
11979
+ /**
11980
+ * Assemble a ptable def directly from recipes. Each secondary recipe is its own
11981
+ * outer-joined subtree: `getQuery()` encodes its linker chain, and its
11982
+ * hit-/queries-qualifications are derived on the spot via {@link hitQualifications}
11983
+ * / {@link queriesQualifications} — no pre-extracted DTO. Bare leaves yield empty
11984
+ * qualifications, so plain {@link ColumnRecipe} arrays (e.g. label columns) work
11985
+ * unchanged.
11986
+ */
8996
11987
  function createPTableDefV3(params) {
8997
11988
  let query = {
8998
11989
  type: params.primaryJoinType === "inner" ? "innerJoin" : "fullJoin",
8999
- entries: params.primary.map((a) => toLeaf(a.column, []))
11990
+ entries: params.primary.map((c) => columnToJoinEntry(c, []))
9000
11991
  };
9001
11992
  if (params.secondary.length > 0) query = {
9002
11993
  type: "outerJoin",
9003
11994
  primary: {
9004
11995
  entry: query,
9005
- qualifications: params.secondary.flatMap((g) => params.primary.flatMap((p) => g.primaryQualifications?.[p.column.id] ?? []))
11996
+ qualifications: params.secondary.flatMap((s) => {
11997
+ const quals = queriesQualifications(s);
11998
+ return params.primary.flatMap((p) => quals[p.id] ?? []);
11999
+ })
9006
12000
  },
9007
- secondary: params.secondary.flatMap((g) => g.entries.map((e) => toJoinEntry(e)))
12001
+ secondary: params.secondary.map((c) => columnToJoinEntry(c, hitQualifications(c)))
9008
12002
  };
9009
12003
  if (!isNil(params.filters)) {
9010
12004
  const nonEmpty = distillFilterSpec(params.filters);
@@ -9024,7 +12018,7 @@ function createPTableDefV3(params) {
9024
12018
  sortBy: params.sorting.map((s) => ({
9025
12019
  expression: columnIdToExpr(s.column),
9026
12020
  ascending: s.ascending,
9027
- nullsFirst: !s.naAndAbsentAreLeastValues
12021
+ nullsFirst: s.naAndAbsentAreLeastValues
9028
12022
  }))
9029
12023
  };
9030
12024
  return { query };
@@ -9038,153 +12032,392 @@ function columnIdToExpr(col) {
9038
12032
  value: col.id
9039
12033
  };
9040
12034
  }
9041
- function toLeaf(col, qs) {
12035
+ function columnToJoinEntry(col, qualifications) {
9042
12036
  return {
9043
- entry: {
9044
- type: "column",
9045
- column: col
9046
- },
9047
- qualifications: qs
12037
+ entry: col.getQuery(),
12038
+ qualifications
9048
12039
  };
9049
12040
  }
9050
- function toJoinEntry(e) {
9051
- const qs = e.qualifications ?? [];
9052
- if (isNil(e.linkers) || e.linkers.length === 0) return toLeaf(e.column, qs);
9053
- return {
9054
- ...e.linkers.reduceRight((inner, linker) => ({
9055
- entry: {
9056
- type: "linkerJoin",
9057
- linker: { column: linker },
9058
- secondary: [inner]
9059
- },
9060
- qualifications: []
9061
- }), toLeaf(e.column, [])),
9062
- qualifications: qs
12041
+ //#endregion
12042
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/components/PlDataTable/columnResolver.js
12043
+ function createColumnResolver(columns, deps) {
12044
+ const axisIds = [];
12045
+ for (const c of columns) for (const ax of c.getSpec().axesSpec) axisIds.push(getAxisId(ax));
12046
+ const byFullId = /* @__PURE__ */ new Map();
12047
+ const byPObjectId = /* @__PURE__ */ new Map();
12048
+ for (const c of columns) {
12049
+ byFullId.set(c.id, c);
12050
+ const pid = extractPObjectId(c.id);
12051
+ const existing = byPObjectId.get(pid);
12052
+ if (existing === void 0) byPObjectId.set(pid, c);
12053
+ else if (existing.id !== c.id) deps?.warn?.(`Ambiguous PObjectId ${pid}: recipe ids ${existing.id} and ${c.id} both match — keeping first.`);
12054
+ }
12055
+ return (ref) => {
12056
+ if (ref.type === "axis") return axisIds.some((a) => matchAxisId(ref.id, a)) ? ref : void 0;
12057
+ const hit = byFullId.get(ref.id) ?? byPObjectId.get(extractPObjectId(ref.id));
12058
+ if (hit === void 0) return void 0;
12059
+ return {
12060
+ type: "column",
12061
+ id: hit.id
12062
+ };
9063
12063
  };
9064
12064
  }
9065
12065
  //#endregion
9066
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js
9067
- function createPTableDefV2(params) {
9068
- let coreColumns = params.columns;
9069
- const secondaryColumns = [];
9070
- if (isFunction(params.coreColumnPredicate)) {
9071
- coreColumns = [];
9072
- for (const c of params.columns) if (params.coreColumnPredicate(getColumnIdAndSpec(c))) coreColumns.push(c);
9073
- else secondaryColumns.push(c);
9074
- }
9075
- secondaryColumns.push(...params.labelColumns);
9076
- return createPTableDefV3({
9077
- primary: coreColumns.map((column) => ({ column })),
9078
- secondary: secondaryColumns.map((column) => ({ entries: [{ column }] })),
9079
- primaryJoinType: params.coreJoinType,
9080
- filters: params.filters,
9081
- sorting: params.sorting
9082
- });
12066
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/components/PlDataTable/createPlDataTable/discoverColumns.js
12067
+ /**
12068
+ * Discover columns from sources/anchors and split them into primary
12069
+ * (direct anchor hits — zero-hop, query is a bare column) and secondary
12070
+ * (reached via a linker chain, query carries a join).
12071
+ */
12072
+ function discoverTableColumns(ctx, options) {
12073
+ const discoveredColumns = ColumnsCollection(options.sources, { ctx: ctx.ctx }).discover({
12074
+ ...options.selector,
12075
+ anchors: options.anchors
12076
+ }).getColumns();
12077
+ const primary = [];
12078
+ const secondary = [];
12079
+ for (const col of discoveredColumns) if (isLeafColumn(col)) primary.push(col);
12080
+ else secondary.push(col);
12081
+ return {
12082
+ primary,
12083
+ secondary
12084
+ };
9083
12085
  }
9084
- //#endregion
9085
- //#region ../node_modules/.pnpm/@platforma-sdk+model@1.79.27/node_modules/@platforma-sdk/model/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js
9086
12086
  /**
9087
- * Create p-table spec and handle given ui table state
12087
+ * Discover label columns matching the axes of the given value columns from
12088
+ * ctx providers. Returns a list of label {@link ColumnRecipe}s.
9088
12089
  *
9089
- * @deprecated This version of createPlDataTable is deprecated and will be removed in future. Please migrate to v3 by switching to the new options format and providing necessary information for column discovery and display configuration. See createPlDataTableOptionsV3 for details.
9090
- * @param ctx context
9091
- * @param columns column list
9092
- * @param tableState table ui state
9093
- * @returns PlAgDataTableV2 table source
12090
+ * Primary columns are used as anchors for axis-aware label discovery.
12091
+ * `maxHops` is taken from the longest linker chain present in `columns`.
9094
12092
  */
9095
- function createPlDataTableV2(ctx, columns, tableState, options) {
9096
- if (columns.length === 0) return void 0;
9097
- const tableStateNormalized = upgradePlDataTableStateV2(tableState);
9098
- const allLabelColumns = getAllLabelColumns(ctx.resultPool) ?? [];
9099
- let fullLabelColumns = getMatchingLabelColumns(columns, allLabelColumns);
9100
- fullLabelColumns = deriveLabels(fullLabelColumns, identity, { includeNativeLabel: true }).map((v) => {
9101
- return {
9102
- ...v.value,
9103
- spec: {
9104
- ...v.value.spec,
9105
- annotations: {
9106
- ...v.value.spec.annotations,
9107
- [Annotation.Label]: v.label
9108
- }
9109
- }
9110
- };
12093
+ function discoverLabelColumns(ctx, primary, columns) {
12094
+ if (columns.length === 0) return [];
12095
+ const axes = columns.flatMap((col) => col.getSpec().axesSpec);
12096
+ return ColumnsCollection(void 0, { ctx: ctx.ctx }).discover({
12097
+ include: axes.map((a) => ({
12098
+ name: {
12099
+ type: "exact",
12100
+ value: PColumnName.Label
12101
+ },
12102
+ axes: [{ name: {
12103
+ type: "exact",
12104
+ value: a.name
12105
+ } }]
12106
+ })),
12107
+ anchors: Object.fromEntries(primary.map((col, i) => [`anchor_${i}`, col.getSpec()])),
12108
+ maxHops: columns.reduce((acc, c) => Math.max(acc, collectLinkerIds(c).length), 0)
12109
+ }).getColumns();
12110
+ }
12111
+ //#endregion
12112
+ //#region ../node_modules/.pnpm/@platforma-sdk+model@1.80.2/node_modules/@platforma-sdk/model/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js
12113
+ function createPlDataTableV3(ctx, options) {
12114
+ const state = upgradePlDataTableStateV2(options.tableState);
12115
+ const primaryJoinType = options.primaryJoinType ?? "full";
12116
+ const resolved = resolveInputColumns(ctx, options);
12117
+ if (resolved === void 0) return void 0;
12118
+ const { primary, secondary } = resolved;
12119
+ if (primary.length === 0) return void 0;
12120
+ const { direct, linked } = splitByTopology(secondary);
12121
+ const derivedLabels = deriveAllLabels({
12122
+ columns: [...primary, ...secondary].filter((c) => !isColumnHidden(c.getSpec())).map(toLabelableColumn),
12123
+ deriveLabelsOptions: {
12124
+ includeNativeLabel: true,
12125
+ ...options.labelsOptions
12126
+ }
9111
12127
  });
9112
- const fullColumns = [...columns, ...fullLabelColumns];
9113
- const fullColumnsIds = [...uniqueBy(fullColumns.flatMap((c) => c.spec.axesSpec.map((a) => getAxisId(a))), (a) => canonicalizeJson(a)).map((a) => ({
9114
- type: "axis",
9115
- id: a
9116
- })), ...fullColumns.map((c) => ({
9117
- type: "column",
9118
- id: c.id
9119
- }))];
9120
- const fullColumnsIdsSet = new Set(fullColumnsIds.map((c) => canonicalizeJson(c)));
9121
- const isValidColumnId = (id) => fullColumnsIdsSet.has(id);
9122
- const filters = tableStateNormalized.pTableParams.filters;
9123
- const defaultFilters = options?.filters ?? void 0;
9124
- const firstInvalidFilterColumn = (filters !== null ? collectFilterSpecColumns(filters) : []).find((col) => !isValidColumnId(col));
9125
- if (firstInvalidFilterColumn) throw new Error(`Invalid filter column ${firstInvalidFilterColumn}: column reference does not match the table columns`);
9126
- const firstInvalidDefaultFilterColumn = (defaultFilters !== void 0 ? collectFilterSpecColumns(defaultFilters) : []).find((col) => !isValidColumnId(col));
9127
- if (firstInvalidDefaultFilterColumn) throw new Error(`Invalid default filter column ${firstInvalidDefaultFilterColumn}: column reference does not match the table columns`);
9128
- const userSorting = tableStateNormalized.pTableParams.sorting;
9129
- const sorting = (isEmpty(userSorting) ? options?.sorting : userSorting) ?? [];
9130
- const firstInvalidSortingColumn = sorting.find((s) => !isValidColumnId(canonicalizeJson(s.column)));
9131
- if (firstInvalidSortingColumn) throw new Error(`Invalid sorting column ${JSON.stringify(firstInvalidSortingColumn.column)}: column reference does not match the table columns`);
9132
- const coreJoinType = options?.coreJoinType ?? "full";
9133
- const fullDef = createPTableDefV2({
9134
- columns,
9135
- labelColumns: fullLabelColumns,
9136
- coreJoinType,
12128
+ const allColumnsForRules = [
12129
+ ...primary,
12130
+ ...direct,
12131
+ ...linked,
12132
+ ...collectLinkerSnapshots(linked)
12133
+ ];
12134
+ const visibilityByColId = evaluateRules(options.displayOptions?.visibility ?? [], allColumnsForRules);
12135
+ const orderByColId = evaluateRules(options.displayOptions?.ordering ?? [], allColumnsForRules);
12136
+ const resolver = createColumnResolver([
12137
+ ...primary,
12138
+ ...direct,
12139
+ ...linked.flatMap((lc) => [...collectLinkerColumns(lc), lc])
12140
+ ], { warn: ctx.logWarn.bind(ctx) });
12141
+ const remapedDefaultFilters = remapFilterColumnIds(options.filters, resolver);
12142
+ const filters = filterFilters(concatFilters(state.pTableParams.filters, state.pTableParams.defaultFilters ?? remapedDefaultFilters), resolver);
12143
+ const sorting = filterSorting(resolveSorting(state.pTableParams.sorting, remapSortingColumnIds(options.sorting, resolver)), resolver);
12144
+ const fullDef = createPTableDefV3({
12145
+ primaryJoinType,
12146
+ primary,
12147
+ secondary: [...direct, ...linked],
9137
12148
  filters,
9138
- sorting,
9139
- coreColumnPredicate: options?.coreColumnPredicate
12149
+ sorting
9140
12150
  });
9141
12151
  const fullHandle = ctx.createPTableV2(fullDef);
9142
- const pframeHandle = ctx.createPFrame(fullColumns);
9143
- if (!fullHandle || !pframeHandle) return void 0;
9144
- const hiddenColumns = new Set((() => {
9145
- if (coreJoinType === "inner") return [];
9146
- const hiddenColIds = tableStateNormalized.pTableParams.hiddenColIds;
9147
- if (hiddenColIds !== null) return hiddenColIds.filter((s) => s.type === "column").map((s) => s.id);
9148
- return columns.filter((c) => isColumnOptional(c.spec)).map((c) => c.id);
9149
- })());
9150
- columns.filter((c) => isLinkerColumn(c.spec)).forEach((c) => hiddenColumns.delete(c.id));
9151
- const coreColumnPredicate = options?.coreColumnPredicate;
9152
- if (coreColumnPredicate) columns.flatMap((c) => coreColumnPredicate(getColumnIdAndSpec(c)) ? [c.id] : []).forEach((c) => hiddenColumns.delete(c));
9153
- sorting.map((s) => s.column).filter((c) => c.type === "column").forEach((c) => hiddenColumns.delete(c.id));
9154
- if (filters) collectFilterSpecColumns(filters).flatMap((c) => {
9155
- const obj = parseJson(c);
9156
- return obj.type === "column" ? [obj.id] : [];
9157
- }).forEach((c) => hiddenColumns.delete(c));
9158
- const visibleColumns = columns.filter((c) => !hiddenColumns.has(c.id));
9159
- const visibleLabelColumns = getMatchingLabelColumns(visibleColumns.map(getColumnIdAndSpec), allLabelColumns);
9160
- if (!allPColumnsReady([...visibleColumns, ...visibleLabelColumns])) return void 0;
9161
- const visibleDef = createPTableDefV2({
9162
- columns: visibleColumns,
9163
- labelColumns: visibleLabelColumns,
9164
- coreJoinType,
9165
- filters,
12152
+ const pframeHandle = ctx.createPFrame(uniq([
12153
+ ...primary.map((v) => extractPObjectId(v.id)),
12154
+ ...direct.map((v) => extractPObjectId(v.id)),
12155
+ ...linked.map((v) => extractPObjectId(v.id))
12156
+ ]));
12157
+ const hiddenSpecs = state.pTableParams.hiddenColIds;
12158
+ const hiddenColumnIds = computeHiddenColumns({
12159
+ columns: [
12160
+ ...primary,
12161
+ ...direct,
12162
+ ...linked
12163
+ ],
12164
+ visibilityByColId,
9166
12165
  sorting,
9167
- coreColumnPredicate
12166
+ filters,
12167
+ hiddenSpecs
12168
+ });
12169
+ const visible = {
12170
+ primary,
12171
+ direct: direct.filter((c) => !hiddenColumnIds.has(c.id)),
12172
+ linked: linked.filter((c) => !hiddenColumnIds.has(c.id))
12173
+ };
12174
+ const visibleDef = createPTableDefV3({
12175
+ primaryJoinType,
12176
+ primary,
12177
+ secondary: [...visible.direct, ...visible.linked],
12178
+ filters,
12179
+ sorting
9168
12180
  });
9169
12181
  const visibleHandle = ctx.createPTableV2(visibleDef);
9170
- if (!visibleHandle) return void 0;
12182
+ const columnsMeta = buildColumnsMeta({
12183
+ fullColumns: [
12184
+ ...primary,
12185
+ ...direct,
12186
+ ...linked
12187
+ ],
12188
+ visibleColumns: [
12189
+ ...visible.primary,
12190
+ ...visible.direct,
12191
+ ...visible.linked
12192
+ ],
12193
+ primaryColumns: primary,
12194
+ derivedLabels,
12195
+ visibilityByColId,
12196
+ orderByColId
12197
+ });
9171
12198
  return {
9172
- sourceId: tableStateNormalized.pTableParams.sourceId,
12199
+ sourceId: state.pTableParams.sourceId,
9173
12200
  fullTableHandle: fullHandle,
9174
12201
  fullPframeHandle: pframeHandle,
9175
12202
  visibleTableHandle: visibleHandle,
9176
- defaultFilters
12203
+ defaultFilters: remapedDefaultFilters,
12204
+ columnsMeta
9177
12205
  };
9178
12206
  }
9179
- function getAllLabelColumns(resultPool) {
9180
- return new PColumnCollection().addAxisLabelProvider(resultPool).addColumnProvider(resultPool).getColumns({
9181
- name: PColumnName.Label,
9182
- axes: [{}]
9183
- }, {
9184
- dontWaitAllData: true,
9185
- overrideLabelAnnotation: false
12207
+ /** Normalize either option branch into a {primary, secondary} pair of recipes. */
12208
+ function resolveInputColumns(ctx, options) {
12209
+ if ("primaryColumns" in options) {
12210
+ const primary = options.primaryColumns;
12211
+ const secondary = options.columns ?? [];
12212
+ const labels = discoverLabelColumns(ctx, primary, [...primary, ...secondary]);
12213
+ const primaryIds = new Set(primary.map((c) => c.id));
12214
+ return {
12215
+ primary,
12216
+ secondary: dedupColumns([...secondary, ...labels].filter((c) => !primaryIds.has(c.id)), (c) => c.id, (c) => c.getSpec())
12217
+ };
12218
+ }
12219
+ if (isPlainObject(options.columns)) return discoverTableColumns(ctx, options.columns);
12220
+ }
12221
+ /** Split secondary recipes by query topology: leaves (no linker chain) vs joined. */
12222
+ function splitByTopology(columns) {
12223
+ const direct = [];
12224
+ const linked = [];
12225
+ for (const c of columns) if (isLeafColumn(c)) direct.push(c);
12226
+ else linked.push(c);
12227
+ return {
12228
+ direct,
12229
+ linked
12230
+ };
12231
+ }
12232
+ /** All linker recipes across the given linked columns, deduped by id. */
12233
+ function collectLinkerSnapshots(linked) {
12234
+ return uniqueBy(linked.flatMap((c) => collectLinkerColumns(c)), (c) => c.id);
12235
+ }
12236
+ function toLabelableColumn(col) {
12237
+ return {
12238
+ id: col.id,
12239
+ spec: col.getSpec(),
12240
+ linkerPath: collectLinkerColumns(col).map((linker) => ({ linker: { spec: linker.getSpec() } })),
12241
+ qualifications: {
12242
+ forHit: [...hitQualifications(col)],
12243
+ forQueries: queriesQualifications(col)
12244
+ }
12245
+ };
12246
+ }
12247
+ /**
12248
+ * Compute display metadata as a sidecar keyed by each emitted column's
12249
+ * `ColumnUniversalId` (and axis `AxisId`), instead of baking it into the specs
12250
+ * via `withSpecs`. Spec overrides change a recipe's id, so the same physical
12251
+ * column reached two ways would diverge into two ids and render twice; keeping
12252
+ * meta out of the spec preserves identity and lets dedup collapse such cases.
12253
+ * The UI overlays this onto the engine-emitted specs at render time.
12254
+ */
12255
+ function buildColumnsMeta(params) {
12256
+ const { fullColumns, visibleColumns, primaryColumns, derivedLabels } = params;
12257
+ const { visibilityByColId, orderByColId } = params;
12258
+ const visibleStatus = buildDataStatusMap(visibleColumns);
12259
+ const columns = fullColumns.reduce((acc, c) => {
12260
+ const rc = toRuleColumn(c);
12261
+ acc[c.id] = {
12262
+ label: derivedLabels[c.id],
12263
+ visibility: getEffectiveVisibility(rc, visibilityByColId),
12264
+ order: getOrderPriority(rc, orderByColId),
12265
+ status: visibleStatus[c.id]
12266
+ };
12267
+ return acc;
12268
+ }, {});
12269
+ const primaryAxisKeys = new Set(primaryColumns.flatMap((c) => c.getSpec().axesSpec.map((a) => canonicalizeAxisId(a))));
12270
+ return {
12271
+ columns,
12272
+ axes: fullColumns.reduce((acc, c) => c.getSpec().axesSpec.reduce((inner, ax) => {
12273
+ const key = canonicalizeAxisId(ax);
12274
+ if (inner[key] === void 0) inner[key] = { hidden: !primaryAxisKeys.has(key) };
12275
+ return inner;
12276
+ }, acc), {})
12277
+ };
12278
+ }
12279
+ /** Drop filter leaves whose column references cannot be resolved; rewrite the
12280
+ * resolvable ones through the resolver. Prune empty and/or/not groups. */
12281
+ function filterFilters(filters, resolver) {
12282
+ if (isNil$1(filters)) return filters;
12283
+ const rewriteLeaf = (leaf) => {
12284
+ if (leaf.type === void 0) return leaf;
12285
+ const result = { ...leaf };
12286
+ if ("column" in result) {
12287
+ const c = resolver(result.column);
12288
+ if (isNil$1(c)) return void 0;
12289
+ result.column = c;
12290
+ }
12291
+ if ("rhs" in result) {
12292
+ const c = resolver(result.rhs);
12293
+ if (isNil$1(c)) return void 0;
12294
+ result.rhs = c;
12295
+ }
12296
+ return result;
12297
+ };
12298
+ const prune = (node) => {
12299
+ if (node.type === "and" || node.type === "or") {
12300
+ const kept = node.filters.map((f) => prune(f)).filter((f) => !isNil$1(f));
12301
+ if (kept.length === 0) return void 0;
12302
+ return {
12303
+ type: node.type,
12304
+ filters: kept
12305
+ };
12306
+ }
12307
+ if (node.type === "not") {
12308
+ const inner = prune(node.filter);
12309
+ return isNil$1(inner) ? void 0 : {
12310
+ type: "not",
12311
+ filter: inner
12312
+ };
12313
+ }
12314
+ return rewriteLeaf(node);
12315
+ };
12316
+ return prune(filters);
12317
+ }
12318
+ /** Merge two filter trees into one AND-combined tree. Returns the non-nil one if the other is nil. */
12319
+ function concatFilters(a, b) {
12320
+ if (isNil$1(a)) return b;
12321
+ if (isNil$1(b)) return a;
12322
+ return {
12323
+ ...a,
12324
+ filters: [...a.filters, ...b.filters]
12325
+ };
12326
+ }
12327
+ /** Pick user sorting from state if set, otherwise fall back to options default.
12328
+ * null = user has not touched sorting → use default;
12329
+ * [] = user has explicitly cleared sorting → no sorting (default ignored). */
12330
+ function resolveSorting(userSorting, defaultSorting) {
12331
+ return (isNil$1(userSorting) ? defaultSorting : userSorting) ?? [];
12332
+ }
12333
+ /** Rewrite sorting entries through the resolver; drop those that fail to resolve. */
12334
+ function filterSorting(sorting, resolver) {
12335
+ return sorting.flatMap((s) => {
12336
+ const col = resolver(s.column);
12337
+ return isNil$1(col) ? [] : [{
12338
+ ...s,
12339
+ column: col
12340
+ }];
9186
12341
  });
9187
12342
  }
12343
+ /** Determine which columns should be hidden based on state or optional-column defaults.
12344
+ * Keyed by the recipe's logical {@link ColumnUniversalId} (rich) — variants of
12345
+ * the same physical column are independently visible/hidden. */
12346
+ function computeHiddenColumns(params) {
12347
+ const { columns, visibilityByColId, sorting, filters, hiddenSpecs } = params;
12348
+ const visibilityOf = (c) => getEffectiveVisibility(toRuleColumn(c), visibilityByColId);
12349
+ const alwaysHidden = columns.filter((c) => visibilityOf(c) === "hidden").map((c) => c.id);
12350
+ const optionalHidden = !isNil$1(hiddenSpecs) ? hiddenSpecs.filter((s) => s.type === "column").map((s) => s.id) : columns.filter((c) => visibilityOf(c) === "optional").map((c) => c.id);
12351
+ const initial = [...alwaysHidden, ...optionalHidden];
12352
+ const preserved = collectPreservedColumnIds(sorting, filters);
12353
+ return new Set(initial.filter((id) => !preserved.has(id)));
12354
+ }
12355
+ /** Collect IDs of columns that must remain visible (sorted, filtered). */
12356
+ function collectPreservedColumnIds(sorting, filters) {
12357
+ const sortedIds = (sorting ?? []).map((s) => s.column).filter((c) => c.type === "column").map((c) => c.id);
12358
+ const filterIds = !isNil$1(filters) ? collectFilterSpecColumns(filters).flatMap((c) => c.type === "column" ? [c.id] : []) : [];
12359
+ return /* @__PURE__ */ new Set([...sortedIds, ...filterIds]);
12360
+ }
12361
+ /** Remap column references in sorting entries through the resolver.
12362
+ * Unresolved entries are dropped with a warning (best-effort contract). */
12363
+ function remapSortingColumnIds(sorting, resolver) {
12364
+ return sorting?.flatMap((s) => {
12365
+ const col = resolver(s.column);
12366
+ if (isNil$1(col)) {
12367
+ console.warn(`Sorting column ${JSON.stringify(s.column)} does not match any discovered column — dropped.`);
12368
+ return [];
12369
+ }
12370
+ return [{
12371
+ ...s,
12372
+ column: col
12373
+ }];
12374
+ });
12375
+ }
12376
+ /** Remap column references in a filter tree through the resolver.
12377
+ * Unresolved leaves are dropped with a warning; empty groups are pruned. */
12378
+ function remapFilterColumnIds(filters, resolver) {
12379
+ if (isNil$1(filters)) return filters;
12380
+ const mapLeaf = (leaf) => {
12381
+ if (leaf.type === void 0) return leaf;
12382
+ const result = { ...leaf };
12383
+ if ("column" in result) {
12384
+ const c = resolver(result.column);
12385
+ if (isNil$1(c)) {
12386
+ console.warn(`Filter column ${JSON.stringify(result.column)} does not match any discovered column — dropped.`);
12387
+ return;
12388
+ }
12389
+ result.column = c;
12390
+ }
12391
+ if ("rhs" in result) {
12392
+ const c = resolver(result.rhs);
12393
+ if (isNil$1(c)) {
12394
+ console.warn(`Filter rhs ${JSON.stringify(result.rhs)} does not match any discovered column — dropped.`);
12395
+ return;
12396
+ }
12397
+ result.rhs = c;
12398
+ }
12399
+ return result;
12400
+ };
12401
+ const prune = (node) => {
12402
+ if (node.type === "and" || node.type === "or") {
12403
+ const kept = node.filters.map((f) => prune(f)).filter((f) => !isNil$1(f));
12404
+ if (kept.length === 0) return void 0;
12405
+ return {
12406
+ type: node.type,
12407
+ filters: kept
12408
+ };
12409
+ }
12410
+ if (node.type === "not") {
12411
+ const inner = prune(node.filter);
12412
+ return isNil$1(inner) ? void 0 : {
12413
+ type: "not",
12414
+ filter: inner
12415
+ };
12416
+ }
12417
+ return mapLeaf(node);
12418
+ };
12419
+ return prune(filters);
12420
+ }
9188
12421
  (/* @__PURE__ */ __commonJSMin(((exports, module) => {
9189
12422
  exports = module.exports = stringify;
9190
12423
  exports.getSerialize = serializer;
@@ -9254,8 +12487,8 @@ const StopCodonReplacements = objectType({
9254
12487
  opal: stringType().optional()
9255
12488
  }).optional();
9256
12489
  const BlockArgsValidBase = objectType({
9257
- defaultBlockLabel: stringType(),
9258
- customBlockLabel: stringType(),
12490
+ defaultBlockLabel: stringType().optional(),
12491
+ customBlockLabel: stringType().optional(),
9259
12492
  input: PlRef,
9260
12493
  inputLibrary: PlRef.optional(),
9261
12494
  libraryFile: stringType().transform((v) => v).optional(),
@@ -9544,9 +12777,8 @@ const platforma$1 = BlockModelV3.create(dataModel).prerunArgs((data) => ({
9544
12777
  }).output("started", (ctx) => ctx.outputs !== void 0).output("done", (ctx) => {
9545
12778
  return ctx.outputs !== void 0 ? parseResourceMap(ctx.outputs?.resolve("clns"), (_acc) => true, false).data.map((e) => e.key[0]) : void 0;
9546
12779
  }).outputWithStatus("clones", (ctx) => {
9547
- const collection = ctx.outputs?.resolve("clonotypes")?.parsePObjectCollection();
9548
- if (collection === void 0) return void 0;
9549
- const pColumns = Object.values(collection).filter(isPColumn);
12780
+ const pColumns = ctx.outputs?.resolve("clonotypes")?.getPColumns();
12781
+ if (pColumns === void 0) return void 0;
9550
12782
  return ctx.createPFrame(pColumns);
9551
12783
  }).retentiveOutput("inputOptions", (ctx) => {
9552
12784
  return ctx.resultPool.getOptions((v) => {
@@ -9585,8 +12817,12 @@ const platforma$1 = BlockModelV3.create(dataModel).prerunArgs((data) => ({
9585
12817
  assertFieldType: "Input",
9586
12818
  allowPermanentAbsence: true
9587
12819
  })?.getPColumns();
9588
- if (pCols === void 0) return;
9589
- return createPlDataTableV2(ctx, pCols, ctx.data.tableState);
12820
+ if (pCols === void 0 || pCols.length === 0) return;
12821
+ return createPlDataTableV3(ctx, {
12822
+ primaryColumns: [ColumnLazy.fromColumn(pCols[0])],
12823
+ columns: pCols.slice(1).map((c) => ColumnLazy.fromColumn(c)),
12824
+ tableState: ctx.data.tableState
12825
+ });
9590
12826
  }).output("rawTsvs", (ctx) => {
9591
12827
  if (ctx.outputs === void 0) return void 0;
9592
12828
  const pCols = ctx.outputs?.resolve("clonotypeTables")?.getPColumns();