@okf/ootils 1.31.4 → 1.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.d.ts CHANGED
@@ -1436,6 +1436,18 @@ interface BlockDef {
1436
1436
  compName: string;
1437
1437
  category: 'text' | 'selection' | 'tags' | 'date' | 'number' | 'media' | 'structural' | 'special';
1438
1438
  qualQuant: 'qual' | 'quant' | null;
1439
+ /**
1440
+ * Optional gate that downgrades a block instance from its declared qualQuant unless
1441
+ * ALL conditions match. Used for blocks whose qual-ness depends on a per-instance prop
1442
+ * (e.g. AudioInput is only qual when `props.transcription.enable === true`).
1443
+ *
1444
+ * Each condition is a dotted path into `block.props` with a required value.
1445
+ * No conditions / undefined → block's qualQuant applies unconditionally.
1446
+ */
1447
+ qualConditions?: Array<{
1448
+ propPath: string;
1449
+ equals: any;
1450
+ }>;
1439
1451
  /** Mongoose schema type — the actual value returned to compToTypeMap (e.g. { type: Object }) */
1440
1452
  mongoSchemaType: Record<string, any>;
1441
1453
  /** Elasticsearch mapping shape — used directly by generateMappingsFromTpl */
@@ -1447,8 +1459,6 @@ interface BlockDef {
1447
1459
  plainTextString?: string | null;
1448
1460
  /** Path appended to valuePath for ES/listing search (e.g. 'allText'). null = valuePath used directly. */
1449
1461
  searchField?: string | null;
1450
- /** Path to get display value for table/card rendering (e.g. 'allText'). null = value itself. */
1451
- displayValue?: string | null;
1452
1462
  };
1453
1463
  validation: {
1454
1464
  /** Name of the "is populated" validator fn (resolved by consumer) */
@@ -1566,6 +1576,9 @@ declare const MONGO_SCHEMA_PRESETS: {
1566
1576
  readonly string: {
1567
1577
  readonly type: StringConstructor;
1568
1578
  };
1579
+ readonly array: {
1580
+ readonly type: ArrayConstructor;
1581
+ };
1569
1582
  };
1570
1583
  declare const ELASTIC_MAPPING_PRESETS: {
1571
1584
  readonly largeText: {
@@ -1576,6 +1589,22 @@ declare const ELASTIC_MAPPING_PRESETS: {
1576
1589
  };
1577
1590
  };
1578
1591
  };
1592
+ readonly audioTranscription: {
1593
+ readonly properties: {
1594
+ readonly transcription: {
1595
+ readonly properties: {
1596
+ readonly result: {
1597
+ readonly properties: {
1598
+ readonly finalText: {
1599
+ readonly type: "text";
1600
+ readonly analyzer: "LargeTextAnalyzer";
1601
+ };
1602
+ };
1603
+ };
1604
+ };
1605
+ };
1606
+ };
1607
+ };
1579
1608
  };
1580
1609
  declare const CHUNKING_PRESETS: {
1581
1610
  readonly lexicalSemantic: {
@@ -1616,8 +1645,24 @@ declare class BlockRegistry {
1616
1645
  getQualBlocks(): string[];
1617
1646
  /** Get compType strings for all quant blocks. */
1618
1647
  getQuantBlocks(): string[];
1648
+ /**
1649
+ * Returns true if a specific block instance should be treated as qualitative.
1650
+ * Combines the static `qualQuant` flag with any per-instance `qualConditions`
1651
+ * — e.g. AudioInput is only qual when `props.transcription.enable === true`.
1652
+ */
1653
+ isQualBlock(block: {
1654
+ comp: string;
1655
+ props?: any;
1656
+ }): boolean;
1619
1657
  /** Check if a specific block has a specific capability. */
1620
1658
  hasCapability(compType: string, capability: keyof BlockCapabilities): boolean;
1659
+ /**
1660
+ * Returns true if the block stores its value as an array (Mongo schema type is Array).
1661
+ * Useful for callers that need to know whether to query `valuePath.0` for existence
1662
+ * vs just `valuePath` — empty arrays still pass `$exists: true` on the field itself.
1663
+ * Returns false for unregistered blocks.
1664
+ */
1665
+ isArrayShaped(compType: string): boolean;
1621
1666
  /** Get all registered block descriptors. */
1622
1667
  getAll(): BlockDef[];
1623
1668
  /**
package/dist/node.js CHANGED
@@ -2357,7 +2357,8 @@ var _extractBlocksFromSomeBuilders = ({
2357
2357
  // src/blockRegistry/schemaPresets.ts
2358
2358
  var MONGO_SCHEMA_PRESETS = {
2359
2359
  object: { type: Object },
2360
- string: { type: String }
2360
+ string: { type: String },
2361
+ array: { type: Array }
2361
2362
  };
2362
2363
  var ELASTIC_MAPPING_PRESETS = {
2363
2364
  largeText: {
@@ -2367,6 +2368,24 @@ var ELASTIC_MAPPING_PRESETS = {
2367
2368
  analyzer: "LargeTextAnalyzer"
2368
2369
  }
2369
2370
  }
2371
+ },
2372
+ // Audio file value (array of one object) — only the transcription.result.finalText
2373
+ // is indexed as searchable text. Everything else on the audio object is ignored.
2374
+ audioTranscription: {
2375
+ properties: {
2376
+ transcription: {
2377
+ properties: {
2378
+ result: {
2379
+ properties: {
2380
+ finalText: {
2381
+ type: "text",
2382
+ analyzer: "LargeTextAnalyzer"
2383
+ }
2384
+ }
2385
+ }
2386
+ }
2387
+ }
2388
+ }
2370
2389
  }
2371
2390
  };
2372
2391
  var CHUNKING_PRESETS = {
@@ -2408,8 +2427,7 @@ var LexicalTextEditor = {
2408
2427
  // Field paths
2409
2428
  fieldPaths: {
2410
2429
  plainTextString: "allText",
2411
- searchField: "allText",
2412
- displayValue: "allText"
2430
+ searchField: "allText"
2413
2431
  },
2414
2432
  // Validation
2415
2433
  validation: {
@@ -2447,11 +2465,72 @@ var LexicalTextEditor = {
2447
2465
  chunkingConfig: CHUNKING_PRESETS.lexicalSemantic
2448
2466
  };
2449
2467
 
2468
+ // src/blockRegistry/blocks/AudioInput.ts
2469
+ var AudioInput = {
2470
+ compName: "AudioInput",
2471
+ // Identity
2472
+ category: "media",
2473
+ qualQuant: "qual",
2474
+ // Only qualitative when the tpl block has transcription turned on.
2475
+ // A non-transcribed audio input has no text to analyze, so downstream
2476
+ // qual widgets / search tools should skip it.
2477
+ qualConditions: [
2478
+ { propPath: "transcription.enable", equals: true }
2479
+ ],
2480
+ // Schema
2481
+ mongoSchemaType: MONGO_SCHEMA_PRESETS.array,
2482
+ esMapping: ELASTIC_MAPPING_PRESETS.audioTranscription,
2483
+ // Capabilities
2484
+ capabilities: {
2485
+ // Text lives at transcription.result.finalText on the first (and only) audio item,
2486
+ // derived by the Sarvam adapter into a single canonical field.
2487
+ hasPlainText: true,
2488
+ annotation: true,
2489
+ aiAnnotation: true,
2490
+ aiEnrichment: true,
2491
+ searchable: true,
2492
+ directDataImport: false,
2493
+ csvExport: true,
2494
+ // Translation already happens at the Sarvam level via translateToEnglish flag,
2495
+ // so the autoTranslate pipeline doesn't need to touch this block.
2496
+ translatable: false,
2497
+ documentSummarizer: true,
2498
+ // Transcription payloads can be large — strip from chunk/anno main snapshots
2499
+ // and listing projections.
2500
+ stripFromMainOnAnnoChunkSync: true,
2501
+ excludeFromListingProjection: true
2502
+ },
2503
+ // Field paths
2504
+ // `plainTextString` is the Mongo path consumed by getVal (supports the leading
2505
+ // array index). `searchField` is the ES path — ES flattens arrays of objects
2506
+ // so no index is needed there.
2507
+ fieldPaths: {
2508
+ plainTextString: "0.transcription.result.finalText",
2509
+ searchField: "transcription.result.finalText"
2510
+ },
2511
+ // Validation
2512
+ validation: {
2513
+ populatedCheckFn: "valueArrayIsNotEmpty"
2514
+ },
2515
+ // CSV export — existing transformStructureComp switch routes AudioInput to
2516
+ // formatMediaLinks (outputs audio URLs).
2517
+ csvExport: {
2518
+ transformFn: "formatMediaLinks"
2519
+ },
2520
+ // Chunking — finalText is long free-form speech, so semantic chunking applies.
2521
+ chunkingConfig: CHUNKING_PRESETS.lexicalSemantic,
2522
+ // Content block option — matches the current static entry exactly
2523
+ contentBlockOption: {
2524
+ display: "Audio Input"
2525
+ }
2526
+ };
2527
+
2450
2528
  // src/blockRegistry/registry.ts
2451
2529
  var BlockRegistry = class {
2452
2530
  constructor() {
2453
2531
  this.blocks = /* @__PURE__ */ new Map();
2454
2532
  this.register(LexicalTextEditor);
2533
+ this.register(AudioInput);
2455
2534
  }
2456
2535
  /** Register a block descriptor. */
2457
2536
  register(descriptor) {
@@ -2498,12 +2577,36 @@ var BlockRegistry = class {
2498
2577
  getQuantBlocks() {
2499
2578
  return Array.from(this.blocks.values()).filter((b) => b.qualQuant === "quant").map((b) => b.compName);
2500
2579
  }
2580
+ /**
2581
+ * Returns true if a specific block instance should be treated as qualitative.
2582
+ * Combines the static `qualQuant` flag with any per-instance `qualConditions`
2583
+ * — e.g. AudioInput is only qual when `props.transcription.enable === true`.
2584
+ */
2585
+ isQualBlock(block) {
2586
+ const def = this.blocks.get(block.comp);
2587
+ if (!def || def.qualQuant !== "qual") return false;
2588
+ if (!def.qualConditions?.length) return true;
2589
+ return def.qualConditions.every((cond) => {
2590
+ const value = cond.propPath.split(".").reduce((obj, key) => obj?.[key], block.props);
2591
+ return value === cond.equals;
2592
+ });
2593
+ }
2501
2594
  /** Check if a specific block has a specific capability. */
2502
2595
  hasCapability(compType, capability) {
2503
2596
  const block = this.blocks.get(compType);
2504
2597
  if (!block) return false;
2505
2598
  return !!block.capabilities[capability];
2506
2599
  }
2600
+ /**
2601
+ * Returns true if the block stores its value as an array (Mongo schema type is Array).
2602
+ * Useful for callers that need to know whether to query `valuePath.0` for existence
2603
+ * vs just `valuePath` — empty arrays still pass `$exists: true` on the field itself.
2604
+ * Returns false for unregistered blocks.
2605
+ */
2606
+ isArrayShaped(compType) {
2607
+ const def = this.blocks.get(compType);
2608
+ return def?.mongoSchemaType?.type === Array;
2609
+ }
2507
2610
  /** Get all registered block descriptors. */
2508
2611
  getAll() {
2509
2612
  return Array.from(this.blocks.values());
@@ -3267,7 +3370,9 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
3267
3370
  }
3268
3371
  return templateBlocksCache.get(tpl.kp_content_type);
3269
3372
  };
3373
+ const isPublishingTpl = (tpl) => tpl?.general?.segment === "publishing";
3270
3374
  extractedBlocks.annoTagBlocks = selectedTpls.map((tpl) => {
3375
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
3271
3376
  const allBlocks = getCachedBlocks(tpl);
3272
3377
  const allTagTypes = blockRegistry.getAnnotationEnabledBlocks(allBlocks).flatMap((block) => blockRegistry.getTagTypesConfig(block, smTagTypesConfig).map((d) => d.tagType));
3273
3378
  const uniqueTagTypes = [...new Set(allTagTypes)];
@@ -3280,6 +3385,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
3280
3385
  };
3281
3386
  });
3282
3387
  extractedBlocks.annoEnabledBlocks = selectedTpls.map((tpl) => {
3388
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
3283
3389
  const allBlocks = getCachedBlocks(tpl);
3284
3390
  return {
3285
3391
  contentType: tpl.kp_content_type,
@@ -3287,6 +3393,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
3287
3393
  };
3288
3394
  });
3289
3395
  extractedBlocks.annoRollupBlocks = selectedTpls.map((tpl) => {
3396
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
3290
3397
  const allBlocks = getCachedBlocks(tpl);
3291
3398
  const uniqueTagTypes = Array.from(new Set(
3292
3399
  blockRegistry.getAnnotationEnabledBlocks(allBlocks).flatMap((block) => blockRegistry.getTagTypesConfig(block, smTagTypesConfig)).map((conf) => conf.tagType)
package/dist/node.mjs CHANGED
@@ -2289,7 +2289,8 @@ var _extractBlocksFromSomeBuilders = ({
2289
2289
  // src/blockRegistry/schemaPresets.ts
2290
2290
  var MONGO_SCHEMA_PRESETS = {
2291
2291
  object: { type: Object },
2292
- string: { type: String }
2292
+ string: { type: String },
2293
+ array: { type: Array }
2293
2294
  };
2294
2295
  var ELASTIC_MAPPING_PRESETS = {
2295
2296
  largeText: {
@@ -2299,6 +2300,24 @@ var ELASTIC_MAPPING_PRESETS = {
2299
2300
  analyzer: "LargeTextAnalyzer"
2300
2301
  }
2301
2302
  }
2303
+ },
2304
+ // Audio file value (array of one object) — only the transcription.result.finalText
2305
+ // is indexed as searchable text. Everything else on the audio object is ignored.
2306
+ audioTranscription: {
2307
+ properties: {
2308
+ transcription: {
2309
+ properties: {
2310
+ result: {
2311
+ properties: {
2312
+ finalText: {
2313
+ type: "text",
2314
+ analyzer: "LargeTextAnalyzer"
2315
+ }
2316
+ }
2317
+ }
2318
+ }
2319
+ }
2320
+ }
2302
2321
  }
2303
2322
  };
2304
2323
  var CHUNKING_PRESETS = {
@@ -2340,8 +2359,7 @@ var LexicalTextEditor = {
2340
2359
  // Field paths
2341
2360
  fieldPaths: {
2342
2361
  plainTextString: "allText",
2343
- searchField: "allText",
2344
- displayValue: "allText"
2362
+ searchField: "allText"
2345
2363
  },
2346
2364
  // Validation
2347
2365
  validation: {
@@ -2379,11 +2397,72 @@ var LexicalTextEditor = {
2379
2397
  chunkingConfig: CHUNKING_PRESETS.lexicalSemantic
2380
2398
  };
2381
2399
 
2400
+ // src/blockRegistry/blocks/AudioInput.ts
2401
+ var AudioInput = {
2402
+ compName: "AudioInput",
2403
+ // Identity
2404
+ category: "media",
2405
+ qualQuant: "qual",
2406
+ // Only qualitative when the tpl block has transcription turned on.
2407
+ // A non-transcribed audio input has no text to analyze, so downstream
2408
+ // qual widgets / search tools should skip it.
2409
+ qualConditions: [
2410
+ { propPath: "transcription.enable", equals: true }
2411
+ ],
2412
+ // Schema
2413
+ mongoSchemaType: MONGO_SCHEMA_PRESETS.array,
2414
+ esMapping: ELASTIC_MAPPING_PRESETS.audioTranscription,
2415
+ // Capabilities
2416
+ capabilities: {
2417
+ // Text lives at transcription.result.finalText on the first (and only) audio item,
2418
+ // derived by the Sarvam adapter into a single canonical field.
2419
+ hasPlainText: true,
2420
+ annotation: true,
2421
+ aiAnnotation: true,
2422
+ aiEnrichment: true,
2423
+ searchable: true,
2424
+ directDataImport: false,
2425
+ csvExport: true,
2426
+ // Translation already happens at the Sarvam level via translateToEnglish flag,
2427
+ // so the autoTranslate pipeline doesn't need to touch this block.
2428
+ translatable: false,
2429
+ documentSummarizer: true,
2430
+ // Transcription payloads can be large — strip from chunk/anno main snapshots
2431
+ // and listing projections.
2432
+ stripFromMainOnAnnoChunkSync: true,
2433
+ excludeFromListingProjection: true
2434
+ },
2435
+ // Field paths
2436
+ // `plainTextString` is the Mongo path consumed by getVal (supports the leading
2437
+ // array index). `searchField` is the ES path — ES flattens arrays of objects
2438
+ // so no index is needed there.
2439
+ fieldPaths: {
2440
+ plainTextString: "0.transcription.result.finalText",
2441
+ searchField: "transcription.result.finalText"
2442
+ },
2443
+ // Validation
2444
+ validation: {
2445
+ populatedCheckFn: "valueArrayIsNotEmpty"
2446
+ },
2447
+ // CSV export — existing transformStructureComp switch routes AudioInput to
2448
+ // formatMediaLinks (outputs audio URLs).
2449
+ csvExport: {
2450
+ transformFn: "formatMediaLinks"
2451
+ },
2452
+ // Chunking — finalText is long free-form speech, so semantic chunking applies.
2453
+ chunkingConfig: CHUNKING_PRESETS.lexicalSemantic,
2454
+ // Content block option — matches the current static entry exactly
2455
+ contentBlockOption: {
2456
+ display: "Audio Input"
2457
+ }
2458
+ };
2459
+
2382
2460
  // src/blockRegistry/registry.ts
2383
2461
  var BlockRegistry = class {
2384
2462
  constructor() {
2385
2463
  this.blocks = /* @__PURE__ */ new Map();
2386
2464
  this.register(LexicalTextEditor);
2465
+ this.register(AudioInput);
2387
2466
  }
2388
2467
  /** Register a block descriptor. */
2389
2468
  register(descriptor) {
@@ -2430,12 +2509,36 @@ var BlockRegistry = class {
2430
2509
  getQuantBlocks() {
2431
2510
  return Array.from(this.blocks.values()).filter((b) => b.qualQuant === "quant").map((b) => b.compName);
2432
2511
  }
2512
+ /**
2513
+ * Returns true if a specific block instance should be treated as qualitative.
2514
+ * Combines the static `qualQuant` flag with any per-instance `qualConditions`
2515
+ * — e.g. AudioInput is only qual when `props.transcription.enable === true`.
2516
+ */
2517
+ isQualBlock(block) {
2518
+ const def = this.blocks.get(block.comp);
2519
+ if (!def || def.qualQuant !== "qual") return false;
2520
+ if (!def.qualConditions?.length) return true;
2521
+ return def.qualConditions.every((cond) => {
2522
+ const value = cond.propPath.split(".").reduce((obj, key) => obj?.[key], block.props);
2523
+ return value === cond.equals;
2524
+ });
2525
+ }
2433
2526
  /** Check if a specific block has a specific capability. */
2434
2527
  hasCapability(compType, capability) {
2435
2528
  const block = this.blocks.get(compType);
2436
2529
  if (!block) return false;
2437
2530
  return !!block.capabilities[capability];
2438
2531
  }
2532
+ /**
2533
+ * Returns true if the block stores its value as an array (Mongo schema type is Array).
2534
+ * Useful for callers that need to know whether to query `valuePath.0` for existence
2535
+ * vs just `valuePath` — empty arrays still pass `$exists: true` on the field itself.
2536
+ * Returns false for unregistered blocks.
2537
+ */
2538
+ isArrayShaped(compType) {
2539
+ const def = this.blocks.get(compType);
2540
+ return def?.mongoSchemaType?.type === Array;
2541
+ }
2439
2542
  /** Get all registered block descriptors. */
2440
2543
  getAll() {
2441
2544
  return Array.from(this.blocks.values());
@@ -3199,7 +3302,9 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
3199
3302
  }
3200
3303
  return templateBlocksCache.get(tpl.kp_content_type);
3201
3304
  };
3305
+ const isPublishingTpl = (tpl) => tpl?.general?.segment === "publishing";
3202
3306
  extractedBlocks.annoTagBlocks = selectedTpls.map((tpl) => {
3307
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
3203
3308
  const allBlocks = getCachedBlocks(tpl);
3204
3309
  const allTagTypes = blockRegistry.getAnnotationEnabledBlocks(allBlocks).flatMap((block) => blockRegistry.getTagTypesConfig(block, smTagTypesConfig).map((d) => d.tagType));
3205
3310
  const uniqueTagTypes = [...new Set(allTagTypes)];
@@ -3212,6 +3317,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
3212
3317
  };
3213
3318
  });
3214
3319
  extractedBlocks.annoEnabledBlocks = selectedTpls.map((tpl) => {
3320
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
3215
3321
  const allBlocks = getCachedBlocks(tpl);
3216
3322
  return {
3217
3323
  contentType: tpl.kp_content_type,
@@ -3219,6 +3325,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
3219
3325
  };
3220
3326
  });
3221
3327
  extractedBlocks.annoRollupBlocks = selectedTpls.map((tpl) => {
3328
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
3222
3329
  const allBlocks = getCachedBlocks(tpl);
3223
3330
  const uniqueTagTypes = Array.from(new Set(
3224
3331
  blockRegistry.getAnnotationEnabledBlocks(allBlocks).flatMap((block) => blockRegistry.getTagTypesConfig(block, smTagTypesConfig)).map((conf) => conf.tagType)
@@ -1429,6 +1429,18 @@ interface BlockDef {
1429
1429
  compName: string;
1430
1430
  category: 'text' | 'selection' | 'tags' | 'date' | 'number' | 'media' | 'structural' | 'special';
1431
1431
  qualQuant: 'qual' | 'quant' | null;
1432
+ /**
1433
+ * Optional gate that downgrades a block instance from its declared qualQuant unless
1434
+ * ALL conditions match. Used for blocks whose qual-ness depends on a per-instance prop
1435
+ * (e.g. AudioInput is only qual when `props.transcription.enable === true`).
1436
+ *
1437
+ * Each condition is a dotted path into `block.props` with a required value.
1438
+ * No conditions / undefined → block's qualQuant applies unconditionally.
1439
+ */
1440
+ qualConditions?: Array<{
1441
+ propPath: string;
1442
+ equals: any;
1443
+ }>;
1432
1444
  /** Mongoose schema type — the actual value returned to compToTypeMap (e.g. { type: Object }) */
1433
1445
  mongoSchemaType: Record<string, any>;
1434
1446
  /** Elasticsearch mapping shape — used directly by generateMappingsFromTpl */
@@ -1440,8 +1452,6 @@ interface BlockDef {
1440
1452
  plainTextString?: string | null;
1441
1453
  /** Path appended to valuePath for ES/listing search (e.g. 'allText'). null = valuePath used directly. */
1442
1454
  searchField?: string | null;
1443
- /** Path to get display value for table/card rendering (e.g. 'allText'). null = value itself. */
1444
- displayValue?: string | null;
1445
1455
  };
1446
1456
  validation: {
1447
1457
  /** Name of the "is populated" validator fn (resolved by consumer) */
@@ -1559,6 +1569,9 @@ declare const MONGO_SCHEMA_PRESETS: {
1559
1569
  readonly string: {
1560
1570
  readonly type: StringConstructor;
1561
1571
  };
1572
+ readonly array: {
1573
+ readonly type: ArrayConstructor;
1574
+ };
1562
1575
  };
1563
1576
  declare const ELASTIC_MAPPING_PRESETS: {
1564
1577
  readonly largeText: {
@@ -1569,6 +1582,22 @@ declare const ELASTIC_MAPPING_PRESETS: {
1569
1582
  };
1570
1583
  };
1571
1584
  };
1585
+ readonly audioTranscription: {
1586
+ readonly properties: {
1587
+ readonly transcription: {
1588
+ readonly properties: {
1589
+ readonly result: {
1590
+ readonly properties: {
1591
+ readonly finalText: {
1592
+ readonly type: "text";
1593
+ readonly analyzer: "LargeTextAnalyzer";
1594
+ };
1595
+ };
1596
+ };
1597
+ };
1598
+ };
1599
+ };
1600
+ };
1572
1601
  };
1573
1602
  declare const CHUNKING_PRESETS: {
1574
1603
  readonly lexicalSemantic: {
@@ -1609,8 +1638,24 @@ declare class BlockRegistry {
1609
1638
  getQualBlocks(): string[];
1610
1639
  /** Get compType strings for all quant blocks. */
1611
1640
  getQuantBlocks(): string[];
1641
+ /**
1642
+ * Returns true if a specific block instance should be treated as qualitative.
1643
+ * Combines the static `qualQuant` flag with any per-instance `qualConditions`
1644
+ * — e.g. AudioInput is only qual when `props.transcription.enable === true`.
1645
+ */
1646
+ isQualBlock(block: {
1647
+ comp: string;
1648
+ props?: any;
1649
+ }): boolean;
1612
1650
  /** Check if a specific block has a specific capability. */
1613
1651
  hasCapability(compType: string, capability: keyof BlockCapabilities): boolean;
1652
+ /**
1653
+ * Returns true if the block stores its value as an array (Mongo schema type is Array).
1654
+ * Useful for callers that need to know whether to query `valuePath.0` for existence
1655
+ * vs just `valuePath` — empty arrays still pass `$exists: true` on the field itself.
1656
+ * Returns false for unregistered blocks.
1657
+ */
1658
+ isArrayShaped(compType: string): boolean;
1614
1659
  /** Get all registered block descriptors. */
1615
1660
  getAll(): BlockDef[];
1616
1661
  /**
@@ -1429,6 +1429,18 @@ interface BlockDef {
1429
1429
  compName: string;
1430
1430
  category: 'text' | 'selection' | 'tags' | 'date' | 'number' | 'media' | 'structural' | 'special';
1431
1431
  qualQuant: 'qual' | 'quant' | null;
1432
+ /**
1433
+ * Optional gate that downgrades a block instance from its declared qualQuant unless
1434
+ * ALL conditions match. Used for blocks whose qual-ness depends on a per-instance prop
1435
+ * (e.g. AudioInput is only qual when `props.transcription.enable === true`).
1436
+ *
1437
+ * Each condition is a dotted path into `block.props` with a required value.
1438
+ * No conditions / undefined → block's qualQuant applies unconditionally.
1439
+ */
1440
+ qualConditions?: Array<{
1441
+ propPath: string;
1442
+ equals: any;
1443
+ }>;
1432
1444
  /** Mongoose schema type — the actual value returned to compToTypeMap (e.g. { type: Object }) */
1433
1445
  mongoSchemaType: Record<string, any>;
1434
1446
  /** Elasticsearch mapping shape — used directly by generateMappingsFromTpl */
@@ -1440,8 +1452,6 @@ interface BlockDef {
1440
1452
  plainTextString?: string | null;
1441
1453
  /** Path appended to valuePath for ES/listing search (e.g. 'allText'). null = valuePath used directly. */
1442
1454
  searchField?: string | null;
1443
- /** Path to get display value for table/card rendering (e.g. 'allText'). null = value itself. */
1444
- displayValue?: string | null;
1445
1455
  };
1446
1456
  validation: {
1447
1457
  /** Name of the "is populated" validator fn (resolved by consumer) */
@@ -1559,6 +1569,9 @@ declare const MONGO_SCHEMA_PRESETS: {
1559
1569
  readonly string: {
1560
1570
  readonly type: StringConstructor;
1561
1571
  };
1572
+ readonly array: {
1573
+ readonly type: ArrayConstructor;
1574
+ };
1562
1575
  };
1563
1576
  declare const ELASTIC_MAPPING_PRESETS: {
1564
1577
  readonly largeText: {
@@ -1569,6 +1582,22 @@ declare const ELASTIC_MAPPING_PRESETS: {
1569
1582
  };
1570
1583
  };
1571
1584
  };
1585
+ readonly audioTranscription: {
1586
+ readonly properties: {
1587
+ readonly transcription: {
1588
+ readonly properties: {
1589
+ readonly result: {
1590
+ readonly properties: {
1591
+ readonly finalText: {
1592
+ readonly type: "text";
1593
+ readonly analyzer: "LargeTextAnalyzer";
1594
+ };
1595
+ };
1596
+ };
1597
+ };
1598
+ };
1599
+ };
1600
+ };
1572
1601
  };
1573
1602
  declare const CHUNKING_PRESETS: {
1574
1603
  readonly lexicalSemantic: {
@@ -1609,8 +1638,24 @@ declare class BlockRegistry {
1609
1638
  getQualBlocks(): string[];
1610
1639
  /** Get compType strings for all quant blocks. */
1611
1640
  getQuantBlocks(): string[];
1641
+ /**
1642
+ * Returns true if a specific block instance should be treated as qualitative.
1643
+ * Combines the static `qualQuant` flag with any per-instance `qualConditions`
1644
+ * — e.g. AudioInput is only qual when `props.transcription.enable === true`.
1645
+ */
1646
+ isQualBlock(block: {
1647
+ comp: string;
1648
+ props?: any;
1649
+ }): boolean;
1612
1650
  /** Check if a specific block has a specific capability. */
1613
1651
  hasCapability(compType: string, capability: keyof BlockCapabilities): boolean;
1652
+ /**
1653
+ * Returns true if the block stores its value as an array (Mongo schema type is Array).
1654
+ * Useful for callers that need to know whether to query `valuePath.0` for existence
1655
+ * vs just `valuePath` — empty arrays still pass `$exists: true` on the field itself.
1656
+ * Returns false for unregistered blocks.
1657
+ */
1658
+ isArrayShaped(compType: string): boolean;
1614
1659
  /** Get all registered block descriptors. */
1615
1660
  getAll(): BlockDef[];
1616
1661
  /**