@okf/ootils 1.31.5 → 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.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());
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());
@@ -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
  /**
package/dist/universal.js CHANGED
@@ -379,7 +379,8 @@ var _extractBlocksFromSomeBuilders = ({
379
379
  // src/blockRegistry/schemaPresets.ts
380
380
  var MONGO_SCHEMA_PRESETS = {
381
381
  object: { type: Object },
382
- string: { type: String }
382
+ string: { type: String },
383
+ array: { type: Array }
383
384
  };
384
385
  var ELASTIC_MAPPING_PRESETS = {
385
386
  largeText: {
@@ -389,6 +390,24 @@ var ELASTIC_MAPPING_PRESETS = {
389
390
  analyzer: "LargeTextAnalyzer"
390
391
  }
391
392
  }
393
+ },
394
+ // Audio file value (array of one object) — only the transcription.result.finalText
395
+ // is indexed as searchable text. Everything else on the audio object is ignored.
396
+ audioTranscription: {
397
+ properties: {
398
+ transcription: {
399
+ properties: {
400
+ result: {
401
+ properties: {
402
+ finalText: {
403
+ type: "text",
404
+ analyzer: "LargeTextAnalyzer"
405
+ }
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
392
411
  }
393
412
  };
394
413
  var CHUNKING_PRESETS = {
@@ -430,8 +449,7 @@ var LexicalTextEditor = {
430
449
  // Field paths
431
450
  fieldPaths: {
432
451
  plainTextString: "allText",
433
- searchField: "allText",
434
- displayValue: "allText"
452
+ searchField: "allText"
435
453
  },
436
454
  // Validation
437
455
  validation: {
@@ -469,11 +487,72 @@ var LexicalTextEditor = {
469
487
  chunkingConfig: CHUNKING_PRESETS.lexicalSemantic
470
488
  };
471
489
 
490
+ // src/blockRegistry/blocks/AudioInput.ts
491
+ var AudioInput = {
492
+ compName: "AudioInput",
493
+ // Identity
494
+ category: "media",
495
+ qualQuant: "qual",
496
+ // Only qualitative when the tpl block has transcription turned on.
497
+ // A non-transcribed audio input has no text to analyze, so downstream
498
+ // qual widgets / search tools should skip it.
499
+ qualConditions: [
500
+ { propPath: "transcription.enable", equals: true }
501
+ ],
502
+ // Schema
503
+ mongoSchemaType: MONGO_SCHEMA_PRESETS.array,
504
+ esMapping: ELASTIC_MAPPING_PRESETS.audioTranscription,
505
+ // Capabilities
506
+ capabilities: {
507
+ // Text lives at transcription.result.finalText on the first (and only) audio item,
508
+ // derived by the Sarvam adapter into a single canonical field.
509
+ hasPlainText: true,
510
+ annotation: true,
511
+ aiAnnotation: true,
512
+ aiEnrichment: true,
513
+ searchable: true,
514
+ directDataImport: false,
515
+ csvExport: true,
516
+ // Translation already happens at the Sarvam level via translateToEnglish flag,
517
+ // so the autoTranslate pipeline doesn't need to touch this block.
518
+ translatable: false,
519
+ documentSummarizer: true,
520
+ // Transcription payloads can be large — strip from chunk/anno main snapshots
521
+ // and listing projections.
522
+ stripFromMainOnAnnoChunkSync: true,
523
+ excludeFromListingProjection: true
524
+ },
525
+ // Field paths
526
+ // `plainTextString` is the Mongo path consumed by getVal (supports the leading
527
+ // array index). `searchField` is the ES path — ES flattens arrays of objects
528
+ // so no index is needed there.
529
+ fieldPaths: {
530
+ plainTextString: "0.transcription.result.finalText",
531
+ searchField: "transcription.result.finalText"
532
+ },
533
+ // Validation
534
+ validation: {
535
+ populatedCheckFn: "valueArrayIsNotEmpty"
536
+ },
537
+ // CSV export — existing transformStructureComp switch routes AudioInput to
538
+ // formatMediaLinks (outputs audio URLs).
539
+ csvExport: {
540
+ transformFn: "formatMediaLinks"
541
+ },
542
+ // Chunking — finalText is long free-form speech, so semantic chunking applies.
543
+ chunkingConfig: CHUNKING_PRESETS.lexicalSemantic,
544
+ // Content block option — matches the current static entry exactly
545
+ contentBlockOption: {
546
+ display: "Audio Input"
547
+ }
548
+ };
549
+
472
550
  // src/blockRegistry/registry.ts
473
551
  var BlockRegistry = class {
474
552
  constructor() {
475
553
  this.blocks = /* @__PURE__ */ new Map();
476
554
  this.register(LexicalTextEditor);
555
+ this.register(AudioInput);
477
556
  }
478
557
  /** Register a block descriptor. */
479
558
  register(descriptor) {
@@ -520,12 +599,36 @@ var BlockRegistry = class {
520
599
  getQuantBlocks() {
521
600
  return Array.from(this.blocks.values()).filter((b) => b.qualQuant === "quant").map((b) => b.compName);
522
601
  }
602
+ /**
603
+ * Returns true if a specific block instance should be treated as qualitative.
604
+ * Combines the static `qualQuant` flag with any per-instance `qualConditions`
605
+ * — e.g. AudioInput is only qual when `props.transcription.enable === true`.
606
+ */
607
+ isQualBlock(block) {
608
+ const def = this.blocks.get(block.comp);
609
+ if (!def || def.qualQuant !== "qual") return false;
610
+ if (!def.qualConditions?.length) return true;
611
+ return def.qualConditions.every((cond) => {
612
+ const value = cond.propPath.split(".").reduce((obj, key) => obj?.[key], block.props);
613
+ return value === cond.equals;
614
+ });
615
+ }
523
616
  /** Check if a specific block has a specific capability. */
524
617
  hasCapability(compType, capability) {
525
618
  const block = this.blocks.get(compType);
526
619
  if (!block) return false;
527
620
  return !!block.capabilities[capability];
528
621
  }
622
+ /**
623
+ * Returns true if the block stores its value as an array (Mongo schema type is Array).
624
+ * Useful for callers that need to know whether to query `valuePath.0` for existence
625
+ * vs just `valuePath` — empty arrays still pass `$exists: true` on the field itself.
626
+ * Returns false for unregistered blocks.
627
+ */
628
+ isArrayShaped(compType) {
629
+ const def = this.blocks.get(compType);
630
+ return def?.mongoSchemaType?.type === Array;
631
+ }
529
632
  /** Get all registered block descriptors. */
530
633
  getAll() {
531
634
  return Array.from(this.blocks.values());