@futdevpro/nts-dynamo 1.15.23 → 1.15.29

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.
Files changed (68) hide show
  1. package/README.md +4 -0
  2. package/__documentations/2026-05-17-oai-compatible-providers.md +229 -0
  3. package/_specifications/BACKLOG.md +28 -0
  4. package/build/_models/interfaces/compare-data-options.interface.d.ts +27 -0
  5. package/build/_models/interfaces/compare-data-options.interface.d.ts.map +1 -0
  6. package/build/_models/interfaces/compare-data-options.interface.js +3 -0
  7. package/build/_models/interfaces/compare-data-options.interface.js.map +1 -0
  8. package/build/_models/interfaces/compare-data-result.interface.d.ts +13 -0
  9. package/build/_models/interfaces/compare-data-result.interface.d.ts.map +1 -0
  10. package/build/_models/interfaces/compare-data-result.interface.js +3 -0
  11. package/build/_models/interfaces/compare-data-result.interface.js.map +1 -0
  12. package/build/_modules/ai/_models/interfaces/dynts-ai-cost-event-callback.interface.d.ts +14 -0
  13. package/build/_modules/ai/_models/interfaces/dynts-ai-cost-event-callback.interface.d.ts.map +1 -0
  14. package/build/_modules/ai/_models/interfaces/dynts-ai-cost-event-callback.interface.js +3 -0
  15. package/build/_modules/ai/_models/interfaces/dynts-ai-cost-event-callback.interface.js.map +1 -0
  16. package/build/_modules/ai/_models/interfaces/dynts-ai-cost-event.interface.d.ts +50 -0
  17. package/build/_modules/ai/_models/interfaces/dynts-ai-cost-event.interface.d.ts.map +1 -0
  18. package/build/_modules/ai/_models/interfaces/dynts-ai-cost-event.interface.js +3 -0
  19. package/build/_modules/ai/_models/interfaces/dynts-ai-cost-event.interface.js.map +1 -0
  20. package/build/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.d.ts.map +1 -1
  21. package/build/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.js +32 -0
  22. package/build/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.js.map +1 -1
  23. package/build/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.d.ts.map +1 -1
  24. package/build/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.js +20 -2
  25. package/build/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.js.map +1 -1
  26. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.d.ts +4 -1
  27. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.d.ts.map +1 -1
  28. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.js +28 -1
  29. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.js.map +1 -1
  30. package/build/_modules/ai/_services/ai-provider.service-base.d.ts +21 -0
  31. package/build/_modules/ai/_services/ai-provider.service-base.d.ts.map +1 -1
  32. package/build/_modules/ai/_services/ai-provider.service-base.js +32 -0
  33. package/build/_modules/ai/_services/ai-provider.service-base.js.map +1 -1
  34. package/build/_modules/local-vector-search/_enums/lvs-search-mode.enum.d.ts +17 -1
  35. package/build/_modules/local-vector-search/_enums/lvs-search-mode.enum.d.ts.map +1 -1
  36. package/build/_modules/local-vector-search/_enums/lvs-search-mode.enum.js +16 -0
  37. package/build/_modules/local-vector-search/_enums/lvs-search-mode.enum.js.map +1 -1
  38. package/build/_modules/local-vector-search/_services/lvs-bm25.util.d.ts +89 -0
  39. package/build/_modules/local-vector-search/_services/lvs-bm25.util.d.ts.map +1 -0
  40. package/build/_modules/local-vector-search/_services/lvs-bm25.util.js +190 -0
  41. package/build/_modules/local-vector-search/_services/lvs-bm25.util.js.map +1 -0
  42. package/build/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.d.ts +18 -2
  43. package/build/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.d.ts.map +1 -1
  44. package/build/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.js +57 -3
  45. package/build/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.js.map +1 -1
  46. package/build/_services/base/data.service.d.ts +63 -0
  47. package/build/_services/base/data.service.d.ts.map +1 -1
  48. package/build/_services/base/data.service.js +189 -0
  49. package/build/_services/base/data.service.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/_models/interfaces/compare-data-options.interface.ts +27 -0
  52. package/src/_models/interfaces/compare-data-result.interface.ts +12 -0
  53. package/src/_modules/ai/_models/interfaces/dynts-ai-cost-event-callback.interface.ts +14 -0
  54. package/src/_modules/ai/_models/interfaces/dynts-ai-cost-event.interface.ts +56 -0
  55. package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.spec.ts +92 -0
  56. package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.ts +38 -4
  57. package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.ts +24 -5
  58. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.spec.ts +52 -0
  59. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +39 -10
  60. package/src/_modules/ai/_services/ai-provider.service-base.spec.ts +79 -0
  61. package/src/_modules/ai/_services/ai-provider.service-base.ts +41 -3
  62. package/src/_modules/local-vector-search/_enums/lvs-search-mode.enum.ts +16 -0
  63. package/src/_modules/local-vector-search/_services/lvs-bm25.util.spec.ts +159 -0
  64. package/src/_modules/local-vector-search/_services/lvs-bm25.util.ts +206 -0
  65. package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.spec.ts +135 -0
  66. package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.ts +95 -9
  67. package/src/_services/base/data.service.spec.ts +181 -0
  68. package/src/_services/base/data.service.ts +196 -2
@@ -29,11 +29,30 @@ import {
29
29
 
30
30
  import { DyNTS_getArchivedDBName } from '../../_collections/archive.util';
31
31
  import { DyNTS_global_settings } from '../../_collections/global-settings.const';
32
+ import { DyNTS_CompareData_Options } from '../../_models/interfaces/compare-data-options.interface';
33
+ import { DyNTS_CompareData_Result } from '../../_models/interfaces/compare-data-result.interface';
32
34
  import { DyNTS_DBUpdate } from '../../_models/types/db-update.type';
33
35
  import { DyNTS_GlobalService } from '../core/global.service';
34
36
  import { DyNTS_ArchiveDataService } from './archive-data.service';
35
37
  import { DyNTS_DBService } from './db.service';
36
38
 
39
+
40
+ /**
41
+ * `DyFM_Metadata` field-ek amik auto-discovery modban (fields opcio nelkul)
42
+ * KI vannak hagyva a compareData()-bol. Ezek normal mukodes kozben kezelt
43
+ * mezok (id-allocation, audit timestamps, audit usernames) — szemantikus
44
+ * adatvaltozas-ellenorzeshez irrelevansak.
45
+ *
46
+ * Explicit `fields: ['_id']`-vel meg vizsgaltathato, ha valamiert kell.
47
+ */
48
+ const COMPARE_DATA_METADATA_SKIP_FIELDS: ReadonlySet<string> = new Set<string>([
49
+ '_id',
50
+ '__created',
51
+ '__createdBy',
52
+ '__lastModified',
53
+ '__lastModifiedBy',
54
+ ]);
55
+
37
56
  // TODO: 2 type of archiving service system: within list, or separate db elements
38
57
 
39
58
  /**
@@ -2503,7 +2522,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
2503
2522
  }
2504
2523
 
2505
2524
  protected getDefaultErrorSettings(
2506
- fnName: string,
2525
+ fnName: string,
2507
2526
  error: DyFM_AnyError,
2508
2527
  /** @deprecated we wont support the separate user message in the future, use the message instead */
2509
2528
  useMessageAsUserMessage: boolean = true,
@@ -2514,7 +2533,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
2514
2533
  (error as DyFM_Error)?._message ??
2515
2534
  `${fnName} was UNSUCCESSFUL (${DyNTS_global_settings.systemShortCodeName})`,
2516
2535
  addECToUserMsg: !(error as DyFM_Error)?.__userMessage,
2517
- userMessage: (error as DyFM_Error)?.__userMessage ??
2536
+ userMessage: (error as DyFM_Error)?.__userMessage ??
2518
2537
  (useMessageAsUserMessage ? (error as Error)?.message : this.defaultErrorUserMsg),
2519
2538
  issuer: this.issuer,
2520
2539
  issuerService: this.constructor?.name,
@@ -2522,4 +2541,179 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
2522
2541
  error: error,
2523
2542
  };
2524
2543
  }
2544
+
2545
+
2546
+ // ════════════════════════════════════════════════════════════════════════
2547
+ // GENERIC DATA COMPARE (FR-001)
2548
+ // ════════════════════════════════════════════════════════════════════════
2549
+
2550
+ /**
2551
+ * Generic, field-szintu osszehasonlitas ket adat-objektum kozott.
2552
+ *
2553
+ * **Auto-discovery mod** (`options.fields` nelkul): a metodus mindket
2554
+ * objektum kulcs-uniojan iter, KIVEVE a `DyFM_Metadata` skip-listet
2555
+ * (`_id`, `__created`, `__createdBy`, `__lastModified`, `__lastModifiedBy`).
2556
+ *
2557
+ * **Scope-szukito mod** (`options.fields = [...]`): KIZAROLAG a felsorolt
2558
+ * mezoket vizsgalja. A skip-list IGNORALODIK — explicit fields override.
2559
+ *
2560
+ * **Custom comparator** (`options.customComparators`): per-field override
2561
+ * a default deep-equal helyett (pl. set-equality array-ekre,
2562
+ * case-insensitive string compare-re). A custom function `true`-val signal-ozza
2563
+ * az equality-t.
2564
+ *
2565
+ * **Return:** `'equal'` ha minden vizsgalt field egyezik; `'modified'` ha
2566
+ * legalabb egy elter — ilyenkor `changedFields` tartalmazza a TELJES
2567
+ * mismatch-listat (nem early-return).
2568
+ *
2569
+ * **Throws:**
2570
+ * - `newData` vagy `oldData` null/undefined → `DyFM_Error(400, DyNTS-DS0-CD1)`
2571
+ * - `options.fields = []` ures array → `DyFM_Error(400, DyNTS-DS0-CD2)`
2572
+ *
2573
+ * **Sync method** (nincs I/O szukseglet); a host wrappel-i ha async kell.
2574
+ *
2575
+ * @example
2576
+ * const result = userService.compareData(newUser, oldUser);
2577
+ * if (result.result === 'modified') {
2578
+ * console.log('Changed:', result.changedFields);
2579
+ * }
2580
+ *
2581
+ * @example // Scope-szukites + custom comparator
2582
+ * userService.compareData(newUser, oldUser, {
2583
+ * fields: ['email', 'roles'],
2584
+ * customComparators: {
2585
+ * roles: (a, b) => new Set(a).size === new Set([...a, ...b]).size,
2586
+ * },
2587
+ * });
2588
+ */
2589
+ compareData(
2590
+ newData: T,
2591
+ oldData: T,
2592
+ options?: DyNTS_CompareData_Options<T>,
2593
+ ): DyNTS_CompareData_Result<T> {
2594
+ // Input guard
2595
+ if (newData === null || newData === undefined || oldData === null || oldData === undefined) {
2596
+ throw new DyFM_Error({
2597
+ ...this.getDefaultErrorSettings('compareData', new Error('newData/oldData required')),
2598
+ status: 400,
2599
+ errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DS0-CD1`,
2600
+ message: 'compareData: newData and oldData are required (both must be non-null/undefined)',
2601
+ });
2602
+ }
2603
+
2604
+ if (options?.fields !== undefined && options.fields.length === 0) {
2605
+ throw new DyFM_Error({
2606
+ ...this.getDefaultErrorSettings('compareData', new Error('options.fields must not be empty')),
2607
+ status: 400,
2608
+ errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DS0-CD2`,
2609
+ message: 'compareData: options.fields must not be an empty array',
2610
+ });
2611
+ }
2612
+
2613
+ const fieldsToCheck: (keyof T)[] = this._resolveCompareFields(newData, oldData, options);
2614
+ const comparators: Partial<Record<keyof T, (a: any, b: any) => boolean>> =
2615
+ options?.customComparators ?? {};
2616
+
2617
+ const changedFields: (keyof T)[] = [];
2618
+ for (const field of fieldsToCheck) {
2619
+ const a: any = (newData as any)[field];
2620
+ const b: any = (oldData as any)[field];
2621
+
2622
+ const isEqual: boolean = comparators[field]
2623
+ ? comparators[field]!(a, b)
2624
+ : this._deepEqual(a, b);
2625
+
2626
+ if (!isEqual) {
2627
+ changedFields.push(field);
2628
+ }
2629
+ }
2630
+
2631
+ if (changedFields.length === 0) {
2632
+ return { result: 'equal' };
2633
+ }
2634
+ return { result: 'modified', changedFields: changedFields };
2635
+ }
2636
+
2637
+ /**
2638
+ * Eldonti az osszehasonlitando fields-listat:
2639
+ * - explicit `options.fields` esetan annak masolata (skip-list ignoralt)
2640
+ * - egyebkent `Object.keys(newData) UNION Object.keys(oldData)` minus skip-list
2641
+ */
2642
+ private _resolveCompareFields(
2643
+ newData: T,
2644
+ oldData: T,
2645
+ options?: DyNTS_CompareData_Options<T>,
2646
+ ): (keyof T)[] {
2647
+ if (options?.fields !== undefined) {
2648
+ // Explicit fields — copy-spread (defensive against caller mutation mid-flight)
2649
+ return [...options.fields];
2650
+ }
2651
+
2652
+ const keySet: Set<string> = new Set<string>();
2653
+ for (const k of Object.keys(newData as object)) { keySet.add(k); }
2654
+ for (const k of Object.keys(oldData as object)) { keySet.add(k); }
2655
+
2656
+ const result: (keyof T)[] = [];
2657
+ for (const k of keySet) {
2658
+ if (COMPARE_DATA_METADATA_SKIP_FIELDS.has(k)) { continue; }
2659
+ result.push(k as keyof T);
2660
+ }
2661
+ return result;
2662
+ }
2663
+
2664
+ /**
2665
+ * Deep-equal helper.
2666
+ *
2667
+ * - Primitive (`string`/`number`/`boolean`/`null`/`undefined`): `===` / `Object.is`
2668
+ * (a `NaN === NaN` esetet `Object.is` kezeli helyesen)
2669
+ * - `Date`: `.getTime()` egyenloseg (kulonbozo Date instance-ok same-time-mal egyenlonek)
2670
+ * - Array: length + index-szerinti rekurziv deep-equal
2671
+ * - POJO: keys-union + per-key rekurzio
2672
+ * - Egyeb (RegExp / Map / Set / Buffer): `Object.is` fallback (reference compare)
2673
+ *
2674
+ * NEM kezelt: cyclic references — a hivo objektum-grafja flat / fa kell legyen
2675
+ * (a tipikus FDP data-model esete; cycle eseten stack overflow lesz, ami ertelmes
2676
+ * jelzes a programozonak).
2677
+ */
2678
+ private _deepEqual(a: any, b: any): boolean {
2679
+ if (a === b) { return true; }
2680
+ if (Object.is(a, b)) { return true; }
2681
+
2682
+ // Null/undefined es a masik nem ugyanaz → false
2683
+ if (a === null || a === undefined || b === null || b === undefined) { return false; }
2684
+
2685
+ // Date
2686
+ if (a instanceof Date && b instanceof Date) {
2687
+ return a.getTime() === b.getTime();
2688
+ }
2689
+ if (a instanceof Date || b instanceof Date) { return false; }
2690
+
2691
+ // Array
2692
+ if (Array.isArray(a) && Array.isArray(b)) {
2693
+ if (a.length !== b.length) { return false; }
2694
+ for (let i: number = 0; i < a.length; i++) {
2695
+ if (!this._deepEqual(a[i], b[i])) { return false; }
2696
+ }
2697
+ return true;
2698
+ }
2699
+ if (Array.isArray(a) || Array.isArray(b)) { return false; }
2700
+
2701
+ // POJO (Object.prototype) — keys union, per-key compare
2702
+ if (typeof a === 'object' && typeof b === 'object') {
2703
+ const keysA: string[] = Object.keys(a);
2704
+ const keysB: string[] = Object.keys(b);
2705
+ if (keysA.length !== keysB.length) { return false; }
2706
+ const keysAset: Set<string> = new Set<string>(keysA);
2707
+ for (const k of keysB) {
2708
+ if (!keysAset.has(k)) { return false; }
2709
+ }
2710
+ for (const k of keysA) {
2711
+ if (!this._deepEqual(a[k], b[k])) { return false; }
2712
+ }
2713
+ return true;
2714
+ }
2715
+
2716
+ // Fallback (function, symbol, BigInt, stb.) — strict equality mar nem stimmelt
2717
+ return false;
2718
+ }
2525
2719
  }