hvp-shared 3.4.0 → 3.5.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.
Files changed (36) hide show
  1. package/dist/constants/catalog-item.constants.d.ts +63 -0
  2. package/dist/constants/catalog-item.constants.js +80 -0
  3. package/dist/constants/index.d.ts +4 -0
  4. package/dist/constants/index.js +4 -0
  5. package/dist/{inventory → constants}/qvet-catalog.d.ts +8 -58
  6. package/dist/{inventory → constants}/qvet-catalog.js +10 -133
  7. package/dist/constants/qvet-inventory.d.ts +28 -0
  8. package/dist/constants/qvet-inventory.js +56 -0
  9. package/dist/constants/qvet-warehouses.d.ts +6 -0
  10. package/dist/constants/qvet-warehouses.js +9 -0
  11. package/dist/contracts/catalog-item/index.d.ts +2 -0
  12. package/dist/{inventory → contracts/catalog-item}/index.js +2 -1
  13. package/dist/contracts/catalog-item/requests.d.ts +113 -0
  14. package/dist/contracts/catalog-item/requests.js +7 -0
  15. package/dist/contracts/catalog-item/responses.d.ts +132 -0
  16. package/dist/contracts/catalog-item/responses.js +7 -0
  17. package/dist/contracts/index.d.ts +1 -0
  18. package/dist/contracts/index.js +1 -0
  19. package/dist/index.d.ts +2 -1
  20. package/dist/index.js +2 -1
  21. package/dist/types/catalog-item.types.d.ts +104 -0
  22. package/dist/types/catalog-item.types.js +7 -0
  23. package/dist/types/index.d.ts +3 -0
  24. package/dist/types/index.js +3 -0
  25. package/dist/types/qvet.types.d.ts +21 -0
  26. package/dist/types/qvet.types.js +9 -0
  27. package/dist/types/sync-field.types.d.ts +23 -0
  28. package/dist/types/sync-field.types.js +9 -0
  29. package/dist/utils/qvet-catalog.helpers.d.ts +37 -0
  30. package/dist/utils/qvet-catalog.helpers.js +104 -0
  31. package/dist/utils/sync-field.helpers.d.ts +84 -0
  32. package/dist/utils/sync-field.helpers.js +117 -0
  33. package/dist/utils/sync-field.helpers.test.d.ts +1 -0
  34. package/dist/utils/sync-field.helpers.test.js +149 -0
  35. package/package.json +1 -1
  36. package/dist/inventory/index.d.ts +0 -1
@@ -0,0 +1,132 @@
1
+ /**
2
+ * CatalogItem Response Types
3
+ *
4
+ * Response DTOs for catalog item endpoints.
5
+ */
6
+ import { SyncField } from '../../types/sync-field.types';
7
+ import { UsageType, SyncStatus } from '../../constants/catalog-item.constants';
8
+ import { Warehouse } from '../../types/qvet.types';
9
+ /**
10
+ * Warehouse stock response
11
+ */
12
+ export interface WarehouseStockResponse {
13
+ warehouse: Warehouse;
14
+ currentStock: number;
15
+ minStock: SyncField<number>;
16
+ optimalStock: SyncField<number>;
17
+ }
18
+ /**
19
+ * CatalogItem List Response
20
+ *
21
+ * Simplified item for list views with effective values.
22
+ *
23
+ * @example GET /api/catalog-items
24
+ */
25
+ export interface CatalogItemListResponse {
26
+ id: string;
27
+ qvetCode: number;
28
+ description: string;
29
+ section: string;
30
+ family: string;
31
+ salePrice: number;
32
+ isActive: boolean;
33
+ usageType: UsageType;
34
+ hasPendingChanges: boolean;
35
+ /** Which fields have pending changes */
36
+ pendingFields?: string[];
37
+ syncStatus: SyncStatus;
38
+ lastSyncAt: string;
39
+ }
40
+ /**
41
+ * CatalogItem Detail Response
42
+ *
43
+ * Full item detail with all sync fields.
44
+ *
45
+ * @example GET /api/catalog-items/:id
46
+ */
47
+ export interface CatalogItemDetailResponse {
48
+ id: string;
49
+ qvetCode: number;
50
+ qvetSync: {
51
+ description: SyncField<string>;
52
+ barcode: SyncField<string>;
53
+ reference: SyncField<string>;
54
+ section: SyncField<string>;
55
+ family: SyncField<string>;
56
+ subfamily: SyncField<string>;
57
+ brand: SyncField<string>;
58
+ purchasePrice: SyncField<number>;
59
+ salePrice: SyncField<number>;
60
+ purchaseMargin: SyncField<number>;
61
+ saleMargin: SyncField<number>;
62
+ vatSale: SyncField<number>;
63
+ vatPurchase: SyncField<number>;
64
+ purchaseUnit: SyncField<string>;
65
+ saleUnit: SyncField<string>;
66
+ conversionFactor: SyncField<number>;
67
+ isActive: SyncField<boolean>;
68
+ stockControlType: SyncField<string>;
69
+ stockByWarehouse: WarehouseStockResponse[];
70
+ qvetCreatedAt?: string;
71
+ lastSaleDate?: string;
72
+ };
73
+ hvpData: {
74
+ usageType: UsageType;
75
+ notes?: string;
76
+ internalCategory?: string;
77
+ };
78
+ hasPendingChanges: boolean;
79
+ lastSyncAt: string;
80
+ syncStatus: SyncStatus;
81
+ createdAt: string;
82
+ updatedAt: string;
83
+ updatedBy?: string;
84
+ }
85
+ /**
86
+ * Paginated list response
87
+ */
88
+ export interface CatalogItemPaginatedResponse {
89
+ items: CatalogItemListResponse[];
90
+ meta: {
91
+ total: number;
92
+ page: number;
93
+ limit: number;
94
+ totalPages: number;
95
+ hasNextPage: boolean;
96
+ hasPrevPage: boolean;
97
+ };
98
+ }
99
+ /**
100
+ * Sync status response
101
+ *
102
+ * @example GET /api/catalog-items/sync/status
103
+ */
104
+ export interface CatalogSyncStatusResponse {
105
+ /** Is a sync currently in progress? */
106
+ isRunning: boolean;
107
+ /** Last sync timestamp */
108
+ lastSyncAt?: string;
109
+ /** Last sync result */
110
+ lastSyncResult?: {
111
+ success: boolean;
112
+ itemsProcessed: number;
113
+ itemsCreated: number;
114
+ itemsUpdated: number;
115
+ itemsSkipped: number;
116
+ errors: string[];
117
+ duration: number;
118
+ };
119
+ }
120
+ /**
121
+ * Sync trigger response
122
+ *
123
+ * @example POST /api/catalog-items/sync
124
+ */
125
+ export interface CatalogSyncTriggerResponse {
126
+ /** Sync started successfully */
127
+ started: boolean;
128
+ /** Message */
129
+ message: string;
130
+ /** Estimated items to process */
131
+ estimatedItems?: number;
132
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * CatalogItem Response Types
4
+ *
5
+ * Response DTOs for catalog item endpoints.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -3,3 +3,4 @@
3
3
  * Request and Response types for all API endpoints
4
4
  */
5
5
  export * from './collaborator';
6
+ export * from './catalog-item';
@@ -19,3 +19,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  __exportStar(require("./collaborator"), exports);
22
+ __exportStar(require("./catalog-item"), exports);
package/dist/index.d.ts CHANGED
@@ -6,5 +6,6 @@ export * from './types';
6
6
  export * from './constants';
7
7
  export * from './contracts';
8
8
  export * from './validation';
9
- export * from './inventory';
10
9
  export { debugLog } from './utils/debug-logger';
10
+ export * from './utils/sync-field.helpers';
11
+ export * from './utils/qvet-catalog.helpers';
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ __exportStar(require("./types"), exports);
23
23
  __exportStar(require("./constants"), exports);
24
24
  __exportStar(require("./contracts"), exports);
25
25
  __exportStar(require("./validation"), exports);
26
- __exportStar(require("./inventory"), exports);
27
26
  var debug_logger_1 = require("./utils/debug-logger");
28
27
  Object.defineProperty(exports, "debugLog", { enumerable: true, get: function () { return debug_logger_1.debugLog; } });
28
+ __exportStar(require("./utils/sync-field.helpers"), exports);
29
+ __exportStar(require("./utils/qvet-catalog.helpers"), exports);
@@ -0,0 +1,104 @@
1
+ /**
2
+ * CatalogItem Types
3
+ *
4
+ * Type definitions for catalog items (products/services) that sync with QVET.
5
+ */
6
+ import { SyncField } from './sync-field.types';
7
+ import { UsageType, SyncStatus } from '../constants/catalog-item.constants';
8
+ import { Warehouse } from './qvet.types';
9
+ /**
10
+ * Stock information for a specific warehouse
11
+ */
12
+ export interface WarehouseStock {
13
+ /** Warehouse identifier */
14
+ warehouse: Warehouse;
15
+ /** Current stock quantity (read-only from QVET) */
16
+ currentStock: number;
17
+ /** Minimum stock level (sync with QVET) */
18
+ minStock: SyncField<number>;
19
+ /** Optimal stock level (sync with QVET) */
20
+ optimalStock: SyncField<number>;
21
+ }
22
+ /**
23
+ * QVET Sync Data
24
+ *
25
+ * All fields that sync bidirectionally with QVET.
26
+ * Uses SyncField pattern for tracking pending changes.
27
+ */
28
+ export interface CatalogItemQvetSync {
29
+ description: SyncField<string>;
30
+ barcode: SyncField<string>;
31
+ reference: SyncField<string>;
32
+ section: SyncField<string>;
33
+ family: SyncField<string>;
34
+ subfamily: SyncField<string>;
35
+ brand: SyncField<string>;
36
+ purchasePrice: SyncField<number>;
37
+ salePrice: SyncField<number>;
38
+ purchaseMargin: SyncField<number>;
39
+ saleMargin: SyncField<number>;
40
+ vatSale: SyncField<number>;
41
+ vatPurchase: SyncField<number>;
42
+ purchaseUnit: SyncField<string>;
43
+ saleUnit: SyncField<string>;
44
+ conversionFactor: SyncField<number>;
45
+ isActive: SyncField<boolean>;
46
+ stockControlType: SyncField<string>;
47
+ stockByWarehouse: WarehouseStock[];
48
+ qvetCreatedAt?: string;
49
+ lastSaleDate?: string;
50
+ }
51
+ /**
52
+ * HVP-only Data
53
+ *
54
+ * Fields that only exist in HVP, not synced to QVET.
55
+ */
56
+ export interface CatalogItemHvpData {
57
+ /** How the item is used (sales, internal, etc.) */
58
+ usageType: UsageType;
59
+ /** Internal notes */
60
+ notes?: string;
61
+ /** Internal category for HVP organization */
62
+ internalCategory?: string;
63
+ }
64
+ /**
65
+ * Complete CatalogItem
66
+ *
67
+ * Full catalog item structure as stored in MongoDB.
68
+ */
69
+ export interface CatalogItem {
70
+ /** MongoDB ObjectId as string */
71
+ id: string;
72
+ /** QVET internal code (primary key from QVET) */
73
+ qvetCode: number;
74
+ /** Fields that sync with QVET */
75
+ qvetSync: CatalogItemQvetSync;
76
+ /** HVP-only fields (no sync) */
77
+ hvpData: CatalogItemHvpData;
78
+ /** Has any pending changes (computed) */
79
+ hasPendingChanges: boolean;
80
+ /** Last sync from QVET */
81
+ lastSyncAt: string;
82
+ /** Current sync status */
83
+ syncStatus: SyncStatus;
84
+ createdAt: string;
85
+ updatedAt: string;
86
+ updatedBy?: string;
87
+ }
88
+ /**
89
+ * Simplified CatalogItem for list views
90
+ *
91
+ * Flattened structure using effective values (pending ?? value).
92
+ */
93
+ export interface CatalogItemListItem {
94
+ id: string;
95
+ qvetCode: number;
96
+ description: string;
97
+ section: string;
98
+ family: string;
99
+ salePrice: number;
100
+ isActive: boolean;
101
+ usageType: UsageType;
102
+ hasPendingChanges: boolean;
103
+ syncStatus: SyncStatus;
104
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * CatalogItem Types
4
+ *
5
+ * Type definitions for catalog items (products/services) that sync with QVET.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -6,3 +6,6 @@ export * from './api-response.types';
6
6
  export * from './company-settings.types';
7
7
  export * from './collaborator-fiscal.types';
8
8
  export * from './error-codes.types';
9
+ export * from './sync-field.types';
10
+ export * from './catalog-item.types';
11
+ export * from './qvet.types';
@@ -22,3 +22,6 @@ __exportStar(require("./api-response.types"), exports);
22
22
  __exportStar(require("./company-settings.types"), exports);
23
23
  __exportStar(require("./collaborator-fiscal.types"), exports);
24
24
  __exportStar(require("./error-codes.types"), exports);
25
+ __exportStar(require("./sync-field.types"), exports);
26
+ __exportStar(require("./catalog-item.types"), exports);
27
+ __exportStar(require("./qvet.types"), exports);
@@ -0,0 +1,21 @@
1
+ /**
2
+ * QVET Types
3
+ *
4
+ * Type definitions for QVET system integration.
5
+ * Constants are in constants/qvet-*.ts
6
+ * Helpers are in utils/qvet-catalog.helpers.ts
7
+ */
8
+ import { QVET_SECTIONS, QVET_CATALOG } from '../constants/qvet-catalog';
9
+ import { WAREHOUSES } from '../constants/qvet-warehouses';
10
+ /**
11
+ * QVET Section type (derived from QVET_SECTIONS constant)
12
+ */
13
+ export type QvetSection = (typeof QVET_SECTIONS)[keyof typeof QVET_SECTIONS];
14
+ /**
15
+ * QVET Catalog type (the complete catalog structure)
16
+ */
17
+ export type QvetCatalog = typeof QVET_CATALOG;
18
+ /**
19
+ * Warehouse type (derived from WAREHOUSES constant)
20
+ */
21
+ export type Warehouse = (typeof WAREHOUSES)[number];
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * QVET Types
4
+ *
5
+ * Type definitions for QVET system integration.
6
+ * Constants are in constants/qvet-*.ts
7
+ * Helpers are in utils/qvet-catalog.helpers.ts
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * SyncField<T> - Bidirectional sync pattern
3
+ *
4
+ * Used for fields that sync between an external system (QVET) and HVP.
5
+ * Supports tracking proposed changes that are pending confirmation from the external system.
6
+ *
7
+ * @example
8
+ * // Clean state (no pending change)
9
+ * { value: "Original description", pending: undefined }
10
+ *
11
+ * // With pending change
12
+ * { value: "Original description", pending: "New description" }
13
+ */
14
+ export interface SyncField<T> {
15
+ /** Current value from external system (QVET) */
16
+ value: T;
17
+ /** Proposed change waiting for external confirmation. undefined = no pending change */
18
+ pending: T | undefined;
19
+ }
20
+ /**
21
+ * Creates a new SyncField with an initial value
22
+ */
23
+ export declare function createSyncField<T>(value: T): SyncField<T>;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSyncField = createSyncField;
4
+ /**
5
+ * Creates a new SyncField with an initial value
6
+ */
7
+ function createSyncField(value) {
8
+ return { value, pending: undefined };
9
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * QVET Catalog Helpers
3
+ *
4
+ * Utility functions for working with QVET catalog data.
5
+ */
6
+ /**
7
+ * Get all families for a section
8
+ */
9
+ export declare function getFamiliesForSection(section: string): string[];
10
+ /**
11
+ * Get all subfamilies for a section + family combination
12
+ */
13
+ export declare function getSubfamiliesForFamily(section: string, family: string): readonly string[];
14
+ /**
15
+ * Check if a section exists in the catalog
16
+ */
17
+ export declare function isValidSection(section: string): boolean;
18
+ /**
19
+ * Check if a section is countable (physical inventory)
20
+ */
21
+ export declare function isCountableSection(section: string): boolean;
22
+ /**
23
+ * Check if a family exists within a section
24
+ */
25
+ export declare function isValidFamily(section: string, family: string): boolean;
26
+ /**
27
+ * Check if a subfamily exists within a section + family
28
+ */
29
+ export declare function isValidSubfamily(section: string, family: string, subfamily: string): boolean;
30
+ /**
31
+ * Get sort order for a section (lower = higher priority)
32
+ */
33
+ export declare function getSectionSortOrder(section: string): number;
34
+ /**
35
+ * Check if an item requires expiration date tracking based on section and family
36
+ */
37
+ export declare function requiresExpirationDate(section: string, family: string): boolean;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ /**
3
+ * QVET Catalog Helpers
4
+ *
5
+ * Utility functions for working with QVET catalog data.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.getFamiliesForSection = getFamiliesForSection;
9
+ exports.getSubfamiliesForFamily = getSubfamiliesForFamily;
10
+ exports.isValidSection = isValidSection;
11
+ exports.isCountableSection = isCountableSection;
12
+ exports.isValidFamily = isValidFamily;
13
+ exports.isValidSubfamily = isValidSubfamily;
14
+ exports.getSectionSortOrder = getSectionSortOrder;
15
+ exports.requiresExpirationDate = requiresExpirationDate;
16
+ const qvet_catalog_1 = require("../constants/qvet-catalog");
17
+ const qvet_inventory_1 = require("../constants/qvet-inventory");
18
+ // =============================================================================
19
+ // CATALOG NAVIGATION
20
+ // =============================================================================
21
+ /**
22
+ * Get all families for a section
23
+ */
24
+ function getFamiliesForSection(section) {
25
+ const sectionData = qvet_catalog_1.QVET_CATALOG[section];
26
+ if (!sectionData)
27
+ return [];
28
+ return Object.keys(sectionData);
29
+ }
30
+ /**
31
+ * Get all subfamilies for a section + family combination
32
+ */
33
+ function getSubfamiliesForFamily(section, family) {
34
+ const sectionData = qvet_catalog_1.QVET_CATALOG[section];
35
+ if (!sectionData)
36
+ return [];
37
+ const familyData = sectionData[family];
38
+ if (!familyData)
39
+ return [];
40
+ return familyData;
41
+ }
42
+ // =============================================================================
43
+ // VALIDATION
44
+ // =============================================================================
45
+ /**
46
+ * Check if a section exists in the catalog
47
+ */
48
+ function isValidSection(section) {
49
+ return section in qvet_catalog_1.QVET_CATALOG;
50
+ }
51
+ /**
52
+ * Check if a section is countable (physical inventory)
53
+ */
54
+ function isCountableSection(section) {
55
+ return qvet_inventory_1.INVENTORY_COUNTABLE_SECTIONS_SET.has(section);
56
+ }
57
+ /**
58
+ * Check if a family exists within a section
59
+ */
60
+ function isValidFamily(section, family) {
61
+ const sectionData = qvet_catalog_1.QVET_CATALOG[section];
62
+ if (!sectionData)
63
+ return false;
64
+ return family in sectionData;
65
+ }
66
+ /**
67
+ * Check if a subfamily exists within a section + family
68
+ */
69
+ function isValidSubfamily(section, family, subfamily) {
70
+ const subfamilies = getSubfamiliesForFamily(section, family);
71
+ return subfamilies.includes(subfamily);
72
+ }
73
+ // =============================================================================
74
+ // SORTING
75
+ // =============================================================================
76
+ /**
77
+ * Get sort order for a section (lower = higher priority)
78
+ */
79
+ function getSectionSortOrder(section) {
80
+ const index = qvet_inventory_1.SECTION_SORT_PRIORITY.indexOf(section);
81
+ if (index >= 0) {
82
+ return index;
83
+ }
84
+ // Non-priority sections come after, sorted alphabetically
85
+ return qvet_inventory_1.SECTION_SORT_PRIORITY.length + section.charCodeAt(0);
86
+ }
87
+ // =============================================================================
88
+ // EXPIRATION DATE
89
+ // =============================================================================
90
+ /**
91
+ * Check if an item requires expiration date tracking based on section and family
92
+ */
93
+ function requiresExpirationDate(section, family) {
94
+ // Full section requires expiration
95
+ if (qvet_inventory_1.SECTIONS_REQUIRE_EXPIRATION.includes(section)) {
96
+ return true;
97
+ }
98
+ // Check specific families within sections
99
+ const familiesForSection = qvet_inventory_1.FAMILIES_REQUIRE_EXPIRATION[section];
100
+ if (familiesForSection) {
101
+ return familiesForSection.includes(family);
102
+ }
103
+ return false;
104
+ }
@@ -0,0 +1,84 @@
1
+ import { SyncField } from '../types/sync-field.types';
2
+ /**
3
+ * Get the effective value (pending if exists, otherwise current)
4
+ *
5
+ * @example
6
+ * getValue({ value: "old", pending: "new" }) // "new"
7
+ * getValue({ value: "old", pending: undefined }) // "old"
8
+ */
9
+ export declare function getValue<T>(field: SyncField<T>): T;
10
+ /**
11
+ * Get the external system value (always the synced one, ignores pending)
12
+ *
13
+ * @example
14
+ * getQvetValue({ value: "old", pending: "new" }) // "old"
15
+ */
16
+ export declare function getQvetValue<T>(field: SyncField<T>): T;
17
+ /**
18
+ * Check if field has a pending change
19
+ *
20
+ * @example
21
+ * hasPending({ value: "old", pending: "new" }) // true
22
+ * hasPending({ value: "old", pending: undefined }) // false
23
+ */
24
+ export declare function hasPending<T>(field: SyncField<T>): boolean;
25
+ /**
26
+ * Check if pending value differs from current value
27
+ *
28
+ * @example
29
+ * isDirty({ value: "old", pending: "new" }) // true
30
+ * isDirty({ value: "old", pending: "old" }) // false (same value)
31
+ * isDirty({ value: "old", pending: undefined }) // false
32
+ */
33
+ export declare function isDirty<T>(field: SyncField<T>): boolean;
34
+ /**
35
+ * Set a pending value. If newValue equals current value, clears pending instead.
36
+ *
37
+ * @example
38
+ * setPending({ value: "old", pending: undefined }, "new")
39
+ * // { value: "old", pending: "new" }
40
+ *
41
+ * setPending({ value: "old", pending: undefined }, "old")
42
+ * // { value: "old", pending: undefined } - no change needed
43
+ */
44
+ export declare function setPending<T>(field: SyncField<T>, newValue: T): SyncField<T>;
45
+ /**
46
+ * Clear pending (revert to external system value)
47
+ *
48
+ * @example
49
+ * clearPending({ value: "old", pending: "new" })
50
+ * // { value: "old", pending: undefined }
51
+ */
52
+ export declare function clearPending<T>(field: SyncField<T>): SyncField<T>;
53
+ /**
54
+ * Confirm sync from external system.
55
+ * Updates the value to the new external value and clears pending.
56
+ *
57
+ * @example
58
+ * // External system confirmed our change
59
+ * confirmSync({ value: "old", pending: "new" }, "new")
60
+ * // { value: "new", pending: undefined }
61
+ *
62
+ * // External system has different value
63
+ * confirmSync({ value: "old", pending: undefined }, "updated")
64
+ * // { value: "updated", pending: undefined }
65
+ */
66
+ export declare function confirmSync<T>(field: SyncField<T>, externalValue: T): SyncField<T>;
67
+ /**
68
+ * Apply sync from external system, preserving pending if it differs from new value.
69
+ * Use this when you want to keep local changes during a sync.
70
+ *
71
+ * @example
72
+ * // We have pending, external hasn't changed yet
73
+ * applySyncPreservePending({ value: "old", pending: "new" }, "old")
74
+ * // { value: "old", pending: "new" } - pending preserved
75
+ *
76
+ * // External confirmed our change
77
+ * applySyncPreservePending({ value: "old", pending: "new" }, "new")
78
+ * // { value: "new", pending: undefined } - pending cleared
79
+ *
80
+ * // External changed to something else (conflict scenario)
81
+ * applySyncPreservePending({ value: "old", pending: "new" }, "other")
82
+ * // { value: "other", pending: "new" } - pending preserved, value updated
83
+ */
84
+ export declare function applySyncPreservePending<T>(field: SyncField<T>, externalValue: T): SyncField<T>;