@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/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());
@@ -1669,7 +1772,9 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
1669
1772
  }
1670
1773
  return templateBlocksCache.get(tpl.kp_content_type);
1671
1774
  };
1775
+ const isPublishingTpl = (tpl) => tpl?.general?.segment === "publishing";
1672
1776
  extractedBlocks.annoTagBlocks = selectedTpls.map((tpl) => {
1777
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
1673
1778
  const allBlocks = getCachedBlocks(tpl);
1674
1779
  const allTagTypes = blockRegistry.getAnnotationEnabledBlocks(allBlocks).flatMap((block) => blockRegistry.getTagTypesConfig(block, smTagTypesConfig).map((d) => d.tagType));
1675
1780
  const uniqueTagTypes = [...new Set(allTagTypes)];
@@ -1682,6 +1787,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
1682
1787
  };
1683
1788
  });
1684
1789
  extractedBlocks.annoEnabledBlocks = selectedTpls.map((tpl) => {
1790
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
1685
1791
  const allBlocks = getCachedBlocks(tpl);
1686
1792
  return {
1687
1793
  contentType: tpl.kp_content_type,
@@ -1689,6 +1795,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
1689
1795
  };
1690
1796
  });
1691
1797
  extractedBlocks.annoRollupBlocks = selectedTpls.map((tpl) => {
1798
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
1692
1799
  const allBlocks = getCachedBlocks(tpl);
1693
1800
  const uniqueTagTypes = Array.from(new Set(
1694
1801
  blockRegistry.getAnnotationEnabledBlocks(allBlocks).flatMap((block) => blockRegistry.getTagTypesConfig(block, smTagTypesConfig)).map((conf) => conf.tagType)
@@ -312,7 +312,8 @@ var _extractBlocksFromSomeBuilders = ({
312
312
  // src/blockRegistry/schemaPresets.ts
313
313
  var MONGO_SCHEMA_PRESETS = {
314
314
  object: { type: Object },
315
- string: { type: String }
315
+ string: { type: String },
316
+ array: { type: Array }
316
317
  };
317
318
  var ELASTIC_MAPPING_PRESETS = {
318
319
  largeText: {
@@ -322,6 +323,24 @@ var ELASTIC_MAPPING_PRESETS = {
322
323
  analyzer: "LargeTextAnalyzer"
323
324
  }
324
325
  }
326
+ },
327
+ // Audio file value (array of one object) — only the transcription.result.finalText
328
+ // is indexed as searchable text. Everything else on the audio object is ignored.
329
+ audioTranscription: {
330
+ properties: {
331
+ transcription: {
332
+ properties: {
333
+ result: {
334
+ properties: {
335
+ finalText: {
336
+ type: "text",
337
+ analyzer: "LargeTextAnalyzer"
338
+ }
339
+ }
340
+ }
341
+ }
342
+ }
343
+ }
325
344
  }
326
345
  };
327
346
  var CHUNKING_PRESETS = {
@@ -363,8 +382,7 @@ var LexicalTextEditor = {
363
382
  // Field paths
364
383
  fieldPaths: {
365
384
  plainTextString: "allText",
366
- searchField: "allText",
367
- displayValue: "allText"
385
+ searchField: "allText"
368
386
  },
369
387
  // Validation
370
388
  validation: {
@@ -402,11 +420,72 @@ var LexicalTextEditor = {
402
420
  chunkingConfig: CHUNKING_PRESETS.lexicalSemantic
403
421
  };
404
422
 
423
+ // src/blockRegistry/blocks/AudioInput.ts
424
+ var AudioInput = {
425
+ compName: "AudioInput",
426
+ // Identity
427
+ category: "media",
428
+ qualQuant: "qual",
429
+ // Only qualitative when the tpl block has transcription turned on.
430
+ // A non-transcribed audio input has no text to analyze, so downstream
431
+ // qual widgets / search tools should skip it.
432
+ qualConditions: [
433
+ { propPath: "transcription.enable", equals: true }
434
+ ],
435
+ // Schema
436
+ mongoSchemaType: MONGO_SCHEMA_PRESETS.array,
437
+ esMapping: ELASTIC_MAPPING_PRESETS.audioTranscription,
438
+ // Capabilities
439
+ capabilities: {
440
+ // Text lives at transcription.result.finalText on the first (and only) audio item,
441
+ // derived by the Sarvam adapter into a single canonical field.
442
+ hasPlainText: true,
443
+ annotation: true,
444
+ aiAnnotation: true,
445
+ aiEnrichment: true,
446
+ searchable: true,
447
+ directDataImport: false,
448
+ csvExport: true,
449
+ // Translation already happens at the Sarvam level via translateToEnglish flag,
450
+ // so the autoTranslate pipeline doesn't need to touch this block.
451
+ translatable: false,
452
+ documentSummarizer: true,
453
+ // Transcription payloads can be large — strip from chunk/anno main snapshots
454
+ // and listing projections.
455
+ stripFromMainOnAnnoChunkSync: true,
456
+ excludeFromListingProjection: true
457
+ },
458
+ // Field paths
459
+ // `plainTextString` is the Mongo path consumed by getVal (supports the leading
460
+ // array index). `searchField` is the ES path — ES flattens arrays of objects
461
+ // so no index is needed there.
462
+ fieldPaths: {
463
+ plainTextString: "0.transcription.result.finalText",
464
+ searchField: "transcription.result.finalText"
465
+ },
466
+ // Validation
467
+ validation: {
468
+ populatedCheckFn: "valueArrayIsNotEmpty"
469
+ },
470
+ // CSV export — existing transformStructureComp switch routes AudioInput to
471
+ // formatMediaLinks (outputs audio URLs).
472
+ csvExport: {
473
+ transformFn: "formatMediaLinks"
474
+ },
475
+ // Chunking — finalText is long free-form speech, so semantic chunking applies.
476
+ chunkingConfig: CHUNKING_PRESETS.lexicalSemantic,
477
+ // Content block option — matches the current static entry exactly
478
+ contentBlockOption: {
479
+ display: "Audio Input"
480
+ }
481
+ };
482
+
405
483
  // src/blockRegistry/registry.ts
406
484
  var BlockRegistry = class {
407
485
  constructor() {
408
486
  this.blocks = /* @__PURE__ */ new Map();
409
487
  this.register(LexicalTextEditor);
488
+ this.register(AudioInput);
410
489
  }
411
490
  /** Register a block descriptor. */
412
491
  register(descriptor) {
@@ -453,12 +532,36 @@ var BlockRegistry = class {
453
532
  getQuantBlocks() {
454
533
  return Array.from(this.blocks.values()).filter((b) => b.qualQuant === "quant").map((b) => b.compName);
455
534
  }
535
+ /**
536
+ * Returns true if a specific block instance should be treated as qualitative.
537
+ * Combines the static `qualQuant` flag with any per-instance `qualConditions`
538
+ * — e.g. AudioInput is only qual when `props.transcription.enable === true`.
539
+ */
540
+ isQualBlock(block) {
541
+ const def = this.blocks.get(block.comp);
542
+ if (!def || def.qualQuant !== "qual") return false;
543
+ if (!def.qualConditions?.length) return true;
544
+ return def.qualConditions.every((cond) => {
545
+ const value = cond.propPath.split(".").reduce((obj, key) => obj?.[key], block.props);
546
+ return value === cond.equals;
547
+ });
548
+ }
456
549
  /** Check if a specific block has a specific capability. */
457
550
  hasCapability(compType, capability) {
458
551
  const block = this.blocks.get(compType);
459
552
  if (!block) return false;
460
553
  return !!block.capabilities[capability];
461
554
  }
555
+ /**
556
+ * Returns true if the block stores its value as an array (Mongo schema type is Array).
557
+ * Useful for callers that need to know whether to query `valuePath.0` for existence
558
+ * vs just `valuePath` — empty arrays still pass `$exists: true` on the field itself.
559
+ * Returns false for unregistered blocks.
560
+ */
561
+ isArrayShaped(compType) {
562
+ const def = this.blocks.get(compType);
563
+ return def?.mongoSchemaType?.type === Array;
564
+ }
462
565
  /** Get all registered block descriptors. */
463
566
  getAll() {
464
567
  return Array.from(this.blocks.values());
@@ -1602,7 +1705,9 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
1602
1705
  }
1603
1706
  return templateBlocksCache.get(tpl.kp_content_type);
1604
1707
  };
1708
+ const isPublishingTpl = (tpl) => tpl?.general?.segment === "publishing";
1605
1709
  extractedBlocks.annoTagBlocks = selectedTpls.map((tpl) => {
1710
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
1606
1711
  const allBlocks = getCachedBlocks(tpl);
1607
1712
  const allTagTypes = blockRegistry.getAnnotationEnabledBlocks(allBlocks).flatMap((block) => blockRegistry.getTagTypesConfig(block, smTagTypesConfig).map((d) => d.tagType));
1608
1713
  const uniqueTagTypes = [...new Set(allTagTypes)];
@@ -1615,6 +1720,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
1615
1720
  };
1616
1721
  });
1617
1722
  extractedBlocks.annoEnabledBlocks = selectedTpls.map((tpl) => {
1723
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
1618
1724
  const allBlocks = getCachedBlocks(tpl);
1619
1725
  return {
1620
1726
  contentType: tpl.kp_content_type,
@@ -1622,6 +1728,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls, { smTagTypesConfig } = {}
1622
1728
  };
1623
1729
  });
1624
1730
  extractedBlocks.annoRollupBlocks = selectedTpls.map((tpl) => {
1731
+ if (!isPublishingTpl(tpl)) return { contentType: tpl.kp_content_type, blocks: [] };
1625
1732
  const allBlocks = getCachedBlocks(tpl);
1626
1733
  const uniqueTagTypes = Array.from(new Set(
1627
1734
  blockRegistry.getAnnotationEnabledBlocks(allBlocks).flatMap((block) => blockRegistry.getTagTypesConfig(block, smTagTypesConfig)).map((conf) => conf.tagType)
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.31.4",
6
+ "version": "1.32.0",
7
7
  "description": "Utility functions for both browser and Node.js",
8
8
  "main": "dist/index.js",
9
9
  "module": "dist/index.mjs",