@memberjunction/core-actions 5.24.0 → 5.26.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/custom/files/add-document-content.action.d.ts +20 -0
- package/dist/custom/files/add-document-content.action.d.ts.map +1 -0
- package/dist/custom/files/add-document-content.action.js +74 -0
- package/dist/custom/files/add-document-content.action.js.map +1 -0
- package/dist/custom/files/base-file-storage.action.d.ts +6 -9
- package/dist/custom/files/base-file-storage.action.d.ts.map +1 -1
- package/dist/custom/files/base-file-storage.action.js +14 -39
- package/dist/custom/files/base-file-storage.action.js.map +1 -1
- package/dist/custom/files/create-document.action.d.ts +19 -0
- package/dist/custom/files/create-document.action.d.ts.map +1 -0
- package/dist/custom/files/create-document.action.js +65 -0
- package/dist/custom/files/create-document.action.js.map +1 -0
- package/dist/custom/files/excel-reader.action.js +1 -1
- package/dist/custom/files/excel-reader.action.js.map +1 -1
- package/dist/custom/files/finalize-document.action.d.ts +21 -0
- package/dist/custom/files/finalize-document.action.d.ts.map +1 -0
- package/dist/custom/files/finalize-document.action.js +94 -0
- package/dist/custom/files/finalize-document.action.js.map +1 -0
- package/dist/custom/files/index.d.ts +5 -0
- package/dist/custom/files/index.d.ts.map +1 -1
- package/dist/custom/files/index.js +6 -0
- package/dist/custom/files/index.js.map +1 -1
- package/dist/custom/files/list-storage-providers.action.d.ts.map +1 -1
- package/dist/custom/files/list-storage-providers.action.js +6 -33
- package/dist/custom/files/list-storage-providers.action.js.map +1 -1
- package/dist/custom/files/modify-document-section.action.d.ts +19 -0
- package/dist/custom/files/modify-document-section.action.d.ts.map +1 -0
- package/dist/custom/files/modify-document-section.action.js +85 -0
- package/dist/custom/files/modify-document-section.action.js.map +1 -0
- package/dist/custom/files/pdf-extractor.action.d.ts +8 -14
- package/dist/custom/files/pdf-extractor.action.d.ts.map +1 -1
- package/dist/custom/files/pdf-extractor.action.js +89 -91
- package/dist/custom/files/pdf-extractor.action.js.map +1 -1
- package/dist/custom/files/preview-document.action.d.ts +17 -0
- package/dist/custom/files/preview-document.action.d.ts.map +1 -0
- package/dist/custom/files/preview-document.action.js +50 -0
- package/dist/custom/files/preview-document.action.js.map +1 -0
- package/dist/custom/geo/scheduled-geocoding.action.d.ts +135 -0
- package/dist/custom/geo/scheduled-geocoding.action.d.ts.map +1 -0
- package/dist/custom/geo/scheduled-geocoding.action.js +428 -0
- package/dist/custom/geo/scheduled-geocoding.action.js.map +1 -0
- package/dist/custom/search/search.action.d.ts +67 -0
- package/dist/custom/search/search.action.d.ts.map +1 -0
- package/dist/custom/search/search.action.js +211 -0
- package/dist/custom/search/search.action.js.map +1 -0
- package/dist/custom/utilities/artifact-builder-service.d.ts +139 -0
- package/dist/custom/utilities/artifact-builder-service.d.ts.map +1 -0
- package/dist/custom/utilities/artifact-builder-service.js +338 -0
- package/dist/custom/utilities/artifact-builder-service.js.map +1 -0
- package/dist/custom/utilities/base-file-handler.d.ts +25 -3
- package/dist/custom/utilities/base-file-handler.d.ts.map +1 -1
- package/dist/custom/utilities/base-file-handler.js +81 -28
- package/dist/custom/utilities/base-file-handler.js.map +1 -1
- package/dist/custom/utilities/docx-renderer.d.ts +61 -0
- package/dist/custom/utilities/docx-renderer.d.ts.map +1 -0
- package/dist/custom/utilities/docx-renderer.js +409 -0
- package/dist/custom/utilities/docx-renderer.js.map +1 -0
- package/dist/custom/utilities/external-change-detection.action.d.ts.map +1 -1
- package/dist/custom/utilities/external-change-detection.action.js +7 -0
- package/dist/custom/utilities/external-change-detection.action.js.map +1 -1
- package/dist/custom/utilities/pdf-renderer.d.ts +53 -0
- package/dist/custom/utilities/pdf-renderer.d.ts.map +1 -0
- package/dist/custom/utilities/pdf-renderer.js +315 -0
- package/dist/custom/utilities/pdf-renderer.js.map +1 -0
- package/dist/custom/utilities/xlsx-renderer.d.ts +120 -0
- package/dist/custom/utilities/xlsx-renderer.d.ts.map +1 -0
- package/dist/custom/utilities/xlsx-renderer.js +165 -0
- package/dist/custom/utilities/xlsx-renderer.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +32 -27
- package/dist/custom/files/excel-writer.action.d.ts +0 -88
- package/dist/custom/files/excel-writer.action.d.ts.map +0 -1
- package/dist/custom/files/excel-writer.action.js +0 -326
- package/dist/custom/files/excel-writer.action.js.map +0 -1
- package/dist/custom/files/pdf-generator.action.d.ts +0 -66
- package/dist/custom/files/pdf-generator.action.d.ts.map +0 -1
- package/dist/custom/files/pdf-generator.action.js +0 -254
- package/dist/custom/files/pdf-generator.action.js.map +0 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
|
|
2
|
+
import { BaseAction } from '@memberjunction/actions';
|
|
3
|
+
/**
|
|
4
|
+
* Scheduled geocoding maintenance action that handles three tasks:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Missing records** — Finds records in geo-enabled entities that have
|
|
7
|
+
* non-null geo fields but no RecordGeoCode row, and geocodes them.
|
|
8
|
+
* 2. **Failed retries** — Retries RecordGeoCode rows with Status='failed'
|
|
9
|
+
* up to a configurable max retry count.
|
|
10
|
+
* 3. **Orphan cleanup** — Removes RecordGeoCode rows whose source entity
|
|
11
|
+
* record no longer exists.
|
|
12
|
+
*
|
|
13
|
+
* ## Parameters
|
|
14
|
+
* - **BatchSize** (default 10) — Number of records to geocode **concurrently**
|
|
15
|
+
* in each parallel batch. Controls API rate pressure. Google Geocoding API
|
|
16
|
+
* allows 50 QPS, so 10 is conservative and leaves headroom.
|
|
17
|
+
* - **MaxTotalRecords** (default unlimited) — Optional hard cap on the total
|
|
18
|
+
* number of records processed in a single run. When null/0, processes all
|
|
19
|
+
* pending records until exhausted.
|
|
20
|
+
* - **MaxRetries** (default 5) — Maximum retry count for failed geocoding
|
|
21
|
+
* attempts before a record is considered permanently failed.
|
|
22
|
+
*
|
|
23
|
+
* ## Cache Invalidation
|
|
24
|
+
* After geocoding each record, the action loads the parent entity record
|
|
25
|
+
* and fires a synthetic BaseEntity 'save' event so that any cached RunView
|
|
26
|
+
* results containing stale lat/lng (from the RecordGeoCode JOIN) are
|
|
27
|
+
* invalidated. This ensures the server cache stays consistent.
|
|
28
|
+
*
|
|
29
|
+
* Designed to run on a schedule (every few hours) as a safety net for records
|
|
30
|
+
* that bypass BaseEntity.Save() (bulk SQL imports, direct DB operations).
|
|
31
|
+
*/
|
|
32
|
+
export declare class ScheduledGeocodingAction extends BaseAction {
|
|
33
|
+
private static readonly DEFAULT_MAX_RETRIES;
|
|
34
|
+
private static readonly DEFAULT_BATCH_SIZE;
|
|
35
|
+
protected InternalRunAction(params: RunActionParams): Promise<ActionResultSimple>;
|
|
36
|
+
/**
|
|
37
|
+
* Find records in geo-enabled entities that have no RecordGeoCode row
|
|
38
|
+
* and geocode them. Processes ALL missing records (or up to maxTotal),
|
|
39
|
+
* geocoding in parallel batches of batchSize.
|
|
40
|
+
*/
|
|
41
|
+
private processMissingRecords;
|
|
42
|
+
/**
|
|
43
|
+
* Process all missing RecordGeoCode rows for a single entity.
|
|
44
|
+
* Loads all entity records with non-null geo fields, filters out those
|
|
45
|
+
* that already have a RecordGeoCode row, then geocodes the rest in
|
|
46
|
+
* parallel batches.
|
|
47
|
+
*
|
|
48
|
+
* @param entityInfo - The entity to process
|
|
49
|
+
* @param contextUser - User context for data operations
|
|
50
|
+
* @param batchSize - Number of concurrent geocoding operations per batch
|
|
51
|
+
* @param maxRows - Maximum records to process (0 = unlimited)
|
|
52
|
+
*/
|
|
53
|
+
private processMissingForEntity;
|
|
54
|
+
/**
|
|
55
|
+
* Retry failed geocoding attempts. Loads the source entity record
|
|
56
|
+
* and re-runs GeoCodeSyncService. Processes all eligible failures
|
|
57
|
+
* (or up to maxTotal) in parallel batches.
|
|
58
|
+
*/
|
|
59
|
+
private processFailedRetries;
|
|
60
|
+
/**
|
|
61
|
+
* Load source entity records for a set of RecordGeoCode rows.
|
|
62
|
+
* Skips records whose source entity no longer exists.
|
|
63
|
+
*/
|
|
64
|
+
private loadSourceEntities;
|
|
65
|
+
/**
|
|
66
|
+
* Remove RecordGeoCode rows whose source entity record no longer exists.
|
|
67
|
+
* Processes one entity at a time to keep queries efficient.
|
|
68
|
+
*/
|
|
69
|
+
private cleanupOrphanedRecords;
|
|
70
|
+
/**
|
|
71
|
+
* Geocode a list of entity records in parallel batches, then fire cache
|
|
72
|
+
* invalidation events for each successfully geocoded record.
|
|
73
|
+
*
|
|
74
|
+
* For each record in the batch:
|
|
75
|
+
* 1. Run GeoCodeSyncService.SyncIfChanged to geocode and update RecordGeoCode
|
|
76
|
+
* 2. Fire a synthetic BaseEntity 'save' event with the loaded entity so that
|
|
77
|
+
* LocalCacheManager invalidates any cached RunView results containing stale
|
|
78
|
+
* lat/lng from the RecordGeoCode JOIN
|
|
79
|
+
*
|
|
80
|
+
* @param entities - Pre-loaded BaseEntity instances to geocode
|
|
81
|
+
* @param entityInfo - Entity metadata
|
|
82
|
+
* @param contextUser - User context
|
|
83
|
+
* @param batchSize - Number of concurrent geocoding operations per batch
|
|
84
|
+
*/
|
|
85
|
+
private geocodeBatch;
|
|
86
|
+
/**
|
|
87
|
+
* Geocode a single entity record and fire a cache invalidation event.
|
|
88
|
+
*
|
|
89
|
+
* After geocoding updates the RecordGeoCode row, we need to tell the
|
|
90
|
+
* cache system that this entity record's view data has changed (because
|
|
91
|
+
* the view JOINs to RecordGeoCode for __mj_Latitude/__mj_Longitude).
|
|
92
|
+
* We do this by firing a synthetic BaseEntity 'save' event with the
|
|
93
|
+
* entity instance — the same event that BaseEntity.Save() fires.
|
|
94
|
+
*
|
|
95
|
+
* @returns true if geocoding succeeded, false otherwise
|
|
96
|
+
*/
|
|
97
|
+
private geocodeAndInvalidate;
|
|
98
|
+
/**
|
|
99
|
+
* Fire a synthetic BaseEntity 'save' event via MJGlobal so that
|
|
100
|
+
* LocalCacheManager and BaseEngine listeners pick up the change.
|
|
101
|
+
*
|
|
102
|
+
* This is the same event that BaseEntity.RaiseEvent() fires after
|
|
103
|
+
* a successful Save(), but triggered externally because the record's
|
|
104
|
+
* view data changed due to a RecordGeoCode update (not a direct save).
|
|
105
|
+
*
|
|
106
|
+
* The entity instance is passed as both `component` and `event.baseEntity`
|
|
107
|
+
* so cache handlers can read EntityInfo, PrimaryKeys, and GetAll() —
|
|
108
|
+
* exactly the same contract as a real save event.
|
|
109
|
+
*/
|
|
110
|
+
private fireSyntheticSaveEvent;
|
|
111
|
+
/**
|
|
112
|
+
* Get the geo address fields (non-lat/lng) for an entity.
|
|
113
|
+
* These are the fields that, when non-null, indicate a record
|
|
114
|
+
* should have a geocode.
|
|
115
|
+
*/
|
|
116
|
+
private getGeoAddressFields;
|
|
117
|
+
/**
|
|
118
|
+
* Get the set of RecordIDs that already have a RecordGeoCode row for an entity.
|
|
119
|
+
*/
|
|
120
|
+
private getExistingGeoCodeRecordIds;
|
|
121
|
+
/**
|
|
122
|
+
* Build a RecordID string from an entity's primary key, matching the
|
|
123
|
+
* format used in the view's LEFT JOIN to RecordGeoCode.
|
|
124
|
+
*/
|
|
125
|
+
private buildRecordId;
|
|
126
|
+
/**
|
|
127
|
+
* Extract a numeric parameter with a default value.
|
|
128
|
+
*/
|
|
129
|
+
private getNumericParam;
|
|
130
|
+
/**
|
|
131
|
+
* Extract an optional numeric parameter. Returns null if not provided.
|
|
132
|
+
*/
|
|
133
|
+
private getNullableNumericParam;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=scheduled-geocoding.action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-geocoding.action.d.ts","sourceRoot":"","sources":["../../../src/custom/geo/scheduled-geocoding.action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AASrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBACa,wBAAyB,SAAQ,UAAU;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAK;IAChD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAM;cAEhC,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAyCvF;;;;OAIG;YACW,qBAAqB;IA0BnC;;;;;;;;;;OAUG;YACW,uBAAuB;IAyDrC;;;;OAIG;YACW,oBAAoB;IA2DlC;;;OAGG;YACW,kBAAkB;IA4BhC;;;OAGG;YACW,sBAAsB;IA0DpC;;;;;;;;;;;;;;OAcG;YACW,YAAY;IA0B1B;;;;;;;;;;OAUG;YACW,oBAAoB;IAqBlC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,sBAAsB;IAmB9B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAO3B;;OAEG;YACW,2BAA2B;IAezC;;;OAGG;IACH,OAAO,CAAC,aAAa;IAOrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAMlC"}
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var ScheduledGeocodingAction_1;
|
|
8
|
+
import { BaseAction } from '@memberjunction/actions';
|
|
9
|
+
import { RegisterClass, MJGlobal, MJEventType } from '@memberjunction/global';
|
|
10
|
+
import { RunView, Metadata, LogStatus, LogError, CompositeKey, BaseEntity, BaseEntityEvent } from '@memberjunction/core';
|
|
11
|
+
import { GeoCodeSyncService } from '@memberjunction/geo-core';
|
|
12
|
+
/**
|
|
13
|
+
* Scheduled geocoding maintenance action that handles three tasks:
|
|
14
|
+
*
|
|
15
|
+
* 1. **Missing records** — Finds records in geo-enabled entities that have
|
|
16
|
+
* non-null geo fields but no RecordGeoCode row, and geocodes them.
|
|
17
|
+
* 2. **Failed retries** — Retries RecordGeoCode rows with Status='failed'
|
|
18
|
+
* up to a configurable max retry count.
|
|
19
|
+
* 3. **Orphan cleanup** — Removes RecordGeoCode rows whose source entity
|
|
20
|
+
* record no longer exists.
|
|
21
|
+
*
|
|
22
|
+
* ## Parameters
|
|
23
|
+
* - **BatchSize** (default 10) — Number of records to geocode **concurrently**
|
|
24
|
+
* in each parallel batch. Controls API rate pressure. Google Geocoding API
|
|
25
|
+
* allows 50 QPS, so 10 is conservative and leaves headroom.
|
|
26
|
+
* - **MaxTotalRecords** (default unlimited) — Optional hard cap on the total
|
|
27
|
+
* number of records processed in a single run. When null/0, processes all
|
|
28
|
+
* pending records until exhausted.
|
|
29
|
+
* - **MaxRetries** (default 5) — Maximum retry count for failed geocoding
|
|
30
|
+
* attempts before a record is considered permanently failed.
|
|
31
|
+
*
|
|
32
|
+
* ## Cache Invalidation
|
|
33
|
+
* After geocoding each record, the action loads the parent entity record
|
|
34
|
+
* and fires a synthetic BaseEntity 'save' event so that any cached RunView
|
|
35
|
+
* results containing stale lat/lng (from the RecordGeoCode JOIN) are
|
|
36
|
+
* invalidated. This ensures the server cache stays consistent.
|
|
37
|
+
*
|
|
38
|
+
* Designed to run on a schedule (every few hours) as a safety net for records
|
|
39
|
+
* that bypass BaseEntity.Save() (bulk SQL imports, direct DB operations).
|
|
40
|
+
*/
|
|
41
|
+
let ScheduledGeocodingAction = class ScheduledGeocodingAction extends BaseAction {
|
|
42
|
+
static { ScheduledGeocodingAction_1 = this; }
|
|
43
|
+
static { this.DEFAULT_MAX_RETRIES = 5; }
|
|
44
|
+
static { this.DEFAULT_BATCH_SIZE = 10; }
|
|
45
|
+
async InternalRunAction(params) {
|
|
46
|
+
const contextUser = params.ContextUser;
|
|
47
|
+
if (!contextUser) {
|
|
48
|
+
return { Success: false, ResultCode: 'MISSING_USER', Message: 'ScheduledGeocodingAction requires a context user' };
|
|
49
|
+
}
|
|
50
|
+
const maxRetries = this.getNumericParam(params, 'MaxRetries', ScheduledGeocodingAction_1.DEFAULT_MAX_RETRIES);
|
|
51
|
+
const batchSize = this.getNumericParam(params, 'BatchSize', ScheduledGeocodingAction_1.DEFAULT_BATCH_SIZE);
|
|
52
|
+
const maxTotal = this.getNullableNumericParam(params, 'MaxTotalRecords');
|
|
53
|
+
LogStatus(`ScheduledGeocodingAction: Starting maintenance run (BatchSize=${batchSize}, MaxTotal=${maxTotal ?? 'unlimited'})`);
|
|
54
|
+
const stats = { MissingProcessed: 0, MissingSuccess: 0, RetriesProcessed: 0, RetriesSuccess: 0, OrphansRemoved: 0 };
|
|
55
|
+
// Step 1: Find and geocode missing records
|
|
56
|
+
const missingStats = await this.processMissingRecords(contextUser, batchSize, maxTotal);
|
|
57
|
+
stats.MissingProcessed = missingStats.Processed;
|
|
58
|
+
stats.MissingSuccess = missingStats.Success;
|
|
59
|
+
// Step 2: Retry failed geocoding attempts
|
|
60
|
+
const retryMaxTotal = maxTotal != null ? Math.max(0, maxTotal - stats.MissingProcessed) : null;
|
|
61
|
+
const retryStats = await this.processFailedRetries(contextUser, maxRetries, batchSize, retryMaxTotal);
|
|
62
|
+
stats.RetriesProcessed = retryStats.Processed;
|
|
63
|
+
stats.RetriesSuccess = retryStats.Success;
|
|
64
|
+
// Step 3: Clean up orphaned RecordGeoCode rows
|
|
65
|
+
stats.OrphansRemoved = await this.cleanupOrphanedRecords(contextUser, batchSize);
|
|
66
|
+
LogStatus(`ScheduledGeocodingAction: Complete — Missing: ${stats.MissingProcessed} processed (${stats.MissingSuccess} success), Retries: ${stats.RetriesProcessed} (${stats.RetriesSuccess} success), Orphans: ${stats.OrphansRemoved} removed`);
|
|
67
|
+
return {
|
|
68
|
+
Success: true,
|
|
69
|
+
ResultCode: 'SUCCESS',
|
|
70
|
+
Message: JSON.stringify(stats)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// ================================================================
|
|
74
|
+
// Step 1: Process missing RecordGeoCode rows
|
|
75
|
+
// ================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Find records in geo-enabled entities that have no RecordGeoCode row
|
|
78
|
+
* and geocode them. Processes ALL missing records (or up to maxTotal),
|
|
79
|
+
* geocoding in parallel batches of batchSize.
|
|
80
|
+
*/
|
|
81
|
+
async processMissingRecords(contextUser, batchSize, maxTotal) {
|
|
82
|
+
const md = new Metadata();
|
|
83
|
+
const geoEntities = md.Entities.filter(e => e.SupportsGeoCoding);
|
|
84
|
+
let totalProcessed = 0;
|
|
85
|
+
let totalSuccess = 0;
|
|
86
|
+
for (const entityInfo of geoEntities) {
|
|
87
|
+
if (maxTotal != null && totalProcessed >= maxTotal)
|
|
88
|
+
break;
|
|
89
|
+
const remaining = maxTotal != null ? maxTotal - totalProcessed : null;
|
|
90
|
+
const entityStats = await this.processMissingForEntity(entityInfo, contextUser, batchSize, remaining);
|
|
91
|
+
totalProcessed += entityStats.Processed;
|
|
92
|
+
totalSuccess += entityStats.Success;
|
|
93
|
+
}
|
|
94
|
+
if (totalProcessed > 0) {
|
|
95
|
+
LogStatus(`ScheduledGeocodingAction: Processed ${totalProcessed} missing records (${totalSuccess} geocoded successfully)`);
|
|
96
|
+
}
|
|
97
|
+
return { Processed: totalProcessed, Success: totalSuccess };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Process all missing RecordGeoCode rows for a single entity.
|
|
101
|
+
* Loads all entity records with non-null geo fields, filters out those
|
|
102
|
+
* that already have a RecordGeoCode row, then geocodes the rest in
|
|
103
|
+
* parallel batches.
|
|
104
|
+
*
|
|
105
|
+
* @param entityInfo - The entity to process
|
|
106
|
+
* @param contextUser - User context for data operations
|
|
107
|
+
* @param batchSize - Number of concurrent geocoding operations per batch
|
|
108
|
+
* @param maxRows - Maximum records to process (0 = unlimited)
|
|
109
|
+
*/
|
|
110
|
+
async processMissingForEntity(entityInfo, contextUser, batchSize, maxRows) {
|
|
111
|
+
const rv = new RunView();
|
|
112
|
+
const pkField = entityInfo.FirstPrimaryKey;
|
|
113
|
+
if (!pkField)
|
|
114
|
+
return { Processed: 0, Success: 0 };
|
|
115
|
+
const geoFields = this.getGeoAddressFields(entityInfo);
|
|
116
|
+
if (geoFields.length === 0)
|
|
117
|
+
return { Processed: 0, Success: 0 };
|
|
118
|
+
try {
|
|
119
|
+
// Get all record IDs that already have a RecordGeoCode row
|
|
120
|
+
const existingRecordIds = await this.getExistingGeoCodeRecordIds(entityInfo.ID, contextUser);
|
|
121
|
+
// Load entity records with non-null geo fields
|
|
122
|
+
const nonNullConditions = geoFields.map(f => `${f.Name} IS NOT NULL`).join(' OR ');
|
|
123
|
+
const result = await rv.RunView({
|
|
124
|
+
EntityName: entityInfo.Name,
|
|
125
|
+
ExtraFilter: `(${nonNullConditions})`,
|
|
126
|
+
IgnoreMaxRows: true,
|
|
127
|
+
BypassCache: true,
|
|
128
|
+
ResultType: 'entity_object'
|
|
129
|
+
}, contextUser);
|
|
130
|
+
if (!result.Success || result.Results.length === 0) {
|
|
131
|
+
return { Processed: 0, Success: 0 };
|
|
132
|
+
}
|
|
133
|
+
// Filter to records missing geocodes
|
|
134
|
+
let missingRecords = result.Results
|
|
135
|
+
.filter(entity => {
|
|
136
|
+
const recordId = this.buildRecordId(entity);
|
|
137
|
+
return !existingRecordIds.has(recordId);
|
|
138
|
+
});
|
|
139
|
+
if (maxRows != null) {
|
|
140
|
+
missingRecords = missingRecords.slice(0, maxRows);
|
|
141
|
+
}
|
|
142
|
+
if (missingRecords.length === 0)
|
|
143
|
+
return { Processed: 0, Success: 0 };
|
|
144
|
+
// Geocode in parallel batches
|
|
145
|
+
return await this.geocodeBatch(missingRecords, entityInfo, contextUser, batchSize);
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
149
|
+
LogError(`ScheduledGeocodingAction: Error querying missing records for ${entityInfo.Name}: ${msg}`);
|
|
150
|
+
return { Processed: 0, Success: 0 };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ================================================================
|
|
154
|
+
// Step 2: Retry failed geocoding attempts
|
|
155
|
+
// ================================================================
|
|
156
|
+
/**
|
|
157
|
+
* Retry failed geocoding attempts. Loads the source entity record
|
|
158
|
+
* and re-runs GeoCodeSyncService. Processes all eligible failures
|
|
159
|
+
* (or up to maxTotal) in parallel batches.
|
|
160
|
+
*/
|
|
161
|
+
async processFailedRetries(contextUser, maxRetries, batchSize, maxTotal) {
|
|
162
|
+
const rv = new RunView();
|
|
163
|
+
const failedResult = await rv.RunView({
|
|
164
|
+
EntityName: 'MJ: Record Geo Codes',
|
|
165
|
+
ExtraFilter: `Status='failed' AND RetryCount < ${maxRetries}`,
|
|
166
|
+
IgnoreMaxRows: true,
|
|
167
|
+
OrderBy: 'RetryCount ASC, GeocodedAt ASC',
|
|
168
|
+
ResultType: 'entity_object'
|
|
169
|
+
}, contextUser);
|
|
170
|
+
if (!failedResult.Success || failedResult.Results.length === 0) {
|
|
171
|
+
return { Processed: 0, Success: 0 };
|
|
172
|
+
}
|
|
173
|
+
let records = failedResult.Results;
|
|
174
|
+
if (maxTotal != null) {
|
|
175
|
+
records = records.slice(0, maxTotal);
|
|
176
|
+
}
|
|
177
|
+
LogStatus(`ScheduledGeocodingAction: ${records.length} failed records eligible for retry`);
|
|
178
|
+
const md = new Metadata();
|
|
179
|
+
let totalProcessed = 0;
|
|
180
|
+
let totalSuccess = 0;
|
|
181
|
+
// Group by entity for efficient processing
|
|
182
|
+
const byEntity = new Map();
|
|
183
|
+
for (const geoRecord of records) {
|
|
184
|
+
const key = geoRecord.EntityID;
|
|
185
|
+
let arr = byEntity.get(key);
|
|
186
|
+
if (!arr) {
|
|
187
|
+
arr = [];
|
|
188
|
+
byEntity.set(key, arr);
|
|
189
|
+
}
|
|
190
|
+
arr.push(geoRecord);
|
|
191
|
+
}
|
|
192
|
+
for (const [entityId, geoRecords] of byEntity) {
|
|
193
|
+
const entityInfo = md.EntityByID(entityId);
|
|
194
|
+
if (!entityInfo)
|
|
195
|
+
continue;
|
|
196
|
+
// Load source entity records and geocode them in parallel batches
|
|
197
|
+
const entities = await this.loadSourceEntities(geoRecords, entityInfo, contextUser);
|
|
198
|
+
if (entities.length === 0)
|
|
199
|
+
continue;
|
|
200
|
+
const stats = await this.geocodeBatch(entities, entityInfo, contextUser, batchSize);
|
|
201
|
+
totalProcessed += stats.Processed;
|
|
202
|
+
totalSuccess += stats.Success;
|
|
203
|
+
}
|
|
204
|
+
return { Processed: totalProcessed, Success: totalSuccess };
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Load source entity records for a set of RecordGeoCode rows.
|
|
208
|
+
* Skips records whose source entity no longer exists.
|
|
209
|
+
*/
|
|
210
|
+
async loadSourceEntities(geoRecords, entityInfo, contextUser) {
|
|
211
|
+
const md = new Metadata();
|
|
212
|
+
const entities = [];
|
|
213
|
+
for (const geoRecord of geoRecords) {
|
|
214
|
+
try {
|
|
215
|
+
const entity = await md.GetEntityObject(entityInfo.Name, contextUser);
|
|
216
|
+
const pk = new CompositeKey([{ FieldName: 'ID', Value: geoRecord.RecordID }]);
|
|
217
|
+
const loaded = await entity.InnerLoad(pk);
|
|
218
|
+
if (loaded) {
|
|
219
|
+
entities.push(entity);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Source record doesn't exist or can't be loaded — skip
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return entities;
|
|
227
|
+
}
|
|
228
|
+
// ================================================================
|
|
229
|
+
// Step 3: Orphan cleanup
|
|
230
|
+
// ================================================================
|
|
231
|
+
/**
|
|
232
|
+
* Remove RecordGeoCode rows whose source entity record no longer exists.
|
|
233
|
+
* Processes one entity at a time to keep queries efficient.
|
|
234
|
+
*/
|
|
235
|
+
async cleanupOrphanedRecords(contextUser, batchSize) {
|
|
236
|
+
const rv = new RunView();
|
|
237
|
+
const md = new Metadata();
|
|
238
|
+
let totalRemoved = 0;
|
|
239
|
+
// Get distinct EntityIDs from RecordGeoCode
|
|
240
|
+
const entityResult = await rv.RunView({
|
|
241
|
+
EntityName: 'MJ: Record Geo Codes',
|
|
242
|
+
Fields: ['EntityID'],
|
|
243
|
+
ResultType: 'simple',
|
|
244
|
+
IgnoreMaxRows: true
|
|
245
|
+
}, contextUser);
|
|
246
|
+
if (!entityResult.Success)
|
|
247
|
+
return 0;
|
|
248
|
+
const entityIds = [...new Set(entityResult.Results.map(r => r.EntityID))];
|
|
249
|
+
for (const entityId of entityIds) {
|
|
250
|
+
try {
|
|
251
|
+
const entityInfo = md.EntityByID(entityId);
|
|
252
|
+
if (!entityInfo)
|
|
253
|
+
continue;
|
|
254
|
+
const pkField = entityInfo.FirstPrimaryKey;
|
|
255
|
+
if (!pkField)
|
|
256
|
+
continue;
|
|
257
|
+
const orphanResult = await rv.RunView({
|
|
258
|
+
EntityName: 'MJ: Record Geo Codes',
|
|
259
|
+
ExtraFilter: `EntityID = '${entityId}' AND NOT EXISTS (SELECT 1 FROM ${entityInfo.SchemaName}.${entityInfo.BaseTable} src WHERE CAST(src.${pkField.Name} AS NVARCHAR(450)) = RecordID)`,
|
|
260
|
+
IgnoreMaxRows: true,
|
|
261
|
+
ResultType: 'entity_object'
|
|
262
|
+
}, contextUser);
|
|
263
|
+
if (orphanResult.Success && orphanResult.Results.length > 0) {
|
|
264
|
+
// Delete orphans in parallel batches
|
|
265
|
+
const orphans = orphanResult.Results;
|
|
266
|
+
for (let i = 0; i < orphans.length; i += batchSize) {
|
|
267
|
+
const batch = orphans.slice(i, i + batchSize);
|
|
268
|
+
const results = await Promise.allSettled(batch.map(o => o.Delete()));
|
|
269
|
+
totalRemoved += results.filter(r => r.status === 'fulfilled' && r.value).length;
|
|
270
|
+
}
|
|
271
|
+
LogStatus(`ScheduledGeocodingAction: Removed ${orphanResult.Results.length} orphaned geo records for ${entityInfo.Name}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (e) {
|
|
275
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
276
|
+
LogError(`ScheduledGeocodingAction: Orphan cleanup error for entity ${entityId}: ${msg}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return totalRemoved;
|
|
280
|
+
}
|
|
281
|
+
// ================================================================
|
|
282
|
+
// Core: parallel batch geocoding with cache invalidation
|
|
283
|
+
// ================================================================
|
|
284
|
+
/**
|
|
285
|
+
* Geocode a list of entity records in parallel batches, then fire cache
|
|
286
|
+
* invalidation events for each successfully geocoded record.
|
|
287
|
+
*
|
|
288
|
+
* For each record in the batch:
|
|
289
|
+
* 1. Run GeoCodeSyncService.SyncIfChanged to geocode and update RecordGeoCode
|
|
290
|
+
* 2. Fire a synthetic BaseEntity 'save' event with the loaded entity so that
|
|
291
|
+
* LocalCacheManager invalidates any cached RunView results containing stale
|
|
292
|
+
* lat/lng from the RecordGeoCode JOIN
|
|
293
|
+
*
|
|
294
|
+
* @param entities - Pre-loaded BaseEntity instances to geocode
|
|
295
|
+
* @param entityInfo - Entity metadata
|
|
296
|
+
* @param contextUser - User context
|
|
297
|
+
* @param batchSize - Number of concurrent geocoding operations per batch
|
|
298
|
+
*/
|
|
299
|
+
async geocodeBatch(entities, entityInfo, contextUser, batchSize) {
|
|
300
|
+
let totalSuccess = 0;
|
|
301
|
+
for (let i = 0; i < entities.length; i += batchSize) {
|
|
302
|
+
const batch = entities.slice(i, i + batchSize);
|
|
303
|
+
const results = await Promise.allSettled(batch.map(entity => this.geocodeAndInvalidate(entity, contextUser)));
|
|
304
|
+
const batchSuccess = results.filter(r => r.status === 'fulfilled' && r.value).length;
|
|
305
|
+
totalSuccess += batchSuccess;
|
|
306
|
+
if (entities.length > batchSize) {
|
|
307
|
+
LogStatus(`ScheduledGeocodingAction: ${entityInfo.Name} batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(entities.length / batchSize)} — ${batchSuccess}/${batch.length} success`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return { Processed: entities.length, Success: totalSuccess };
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Geocode a single entity record and fire a cache invalidation event.
|
|
314
|
+
*
|
|
315
|
+
* After geocoding updates the RecordGeoCode row, we need to tell the
|
|
316
|
+
* cache system that this entity record's view data has changed (because
|
|
317
|
+
* the view JOINs to RecordGeoCode for __mj_Latitude/__mj_Longitude).
|
|
318
|
+
* We do this by firing a synthetic BaseEntity 'save' event with the
|
|
319
|
+
* entity instance — the same event that BaseEntity.Save() fires.
|
|
320
|
+
*
|
|
321
|
+
* @returns true if geocoding succeeded, false otherwise
|
|
322
|
+
*/
|
|
323
|
+
async geocodeAndInvalidate(entity, contextUser) {
|
|
324
|
+
try {
|
|
325
|
+
const result = await GeoCodeSyncService.Instance.SyncIfChanged(entity, contextUser);
|
|
326
|
+
if (result) {
|
|
327
|
+
// Geocoding produced new coordinates — fire cache invalidation.
|
|
328
|
+
// Reload the entity to pick up fresh data from the view (including
|
|
329
|
+
// the updated __mj_Latitude/__mj_Longitude from RecordGeoCode JOIN),
|
|
330
|
+
// then raise a save event so LocalCacheManager updates its caches.
|
|
331
|
+
await entity.InnerLoad(entity.PrimaryKey);
|
|
332
|
+
this.fireSyntheticSaveEvent(entity);
|
|
333
|
+
}
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
catch (e) {
|
|
337
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
338
|
+
LogError(`ScheduledGeocodingAction: Failed to geocode ${entity.EntityInfo.Name} record: ${msg}`);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Fire a synthetic BaseEntity 'save' event via MJGlobal so that
|
|
344
|
+
* LocalCacheManager and BaseEngine listeners pick up the change.
|
|
345
|
+
*
|
|
346
|
+
* This is the same event that BaseEntity.RaiseEvent() fires after
|
|
347
|
+
* a successful Save(), but triggered externally because the record's
|
|
348
|
+
* view data changed due to a RecordGeoCode update (not a direct save).
|
|
349
|
+
*
|
|
350
|
+
* The entity instance is passed as both `component` and `event.baseEntity`
|
|
351
|
+
* so cache handlers can read EntityInfo, PrimaryKeys, and GetAll() —
|
|
352
|
+
* exactly the same contract as a real save event.
|
|
353
|
+
*/
|
|
354
|
+
fireSyntheticSaveEvent(entity) {
|
|
355
|
+
const event = new BaseEntityEvent();
|
|
356
|
+
event.type = 'save';
|
|
357
|
+
event.saveSubType = 'update';
|
|
358
|
+
event.baseEntity = entity;
|
|
359
|
+
event.payload = null;
|
|
360
|
+
MJGlobal.Instance.RaiseEvent({
|
|
361
|
+
component: entity,
|
|
362
|
+
event: MJEventType.ComponentEvent,
|
|
363
|
+
eventCode: BaseEntity.BaseEventCode,
|
|
364
|
+
args: event
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
// ================================================================
|
|
368
|
+
// Helpers
|
|
369
|
+
// ================================================================
|
|
370
|
+
/**
|
|
371
|
+
* Get the geo address fields (non-lat/lng) for an entity.
|
|
372
|
+
* These are the fields that, when non-null, indicate a record
|
|
373
|
+
* should have a geocode.
|
|
374
|
+
*/
|
|
375
|
+
getGeoAddressFields(entityInfo) {
|
|
376
|
+
return entityInfo.Fields.filter(f => f.ExtendedType != null && f.ExtendedType.startsWith('Geo') &&
|
|
377
|
+
f.ExtendedType !== 'GeoLatitude' && f.ExtendedType !== 'GeoLongitude');
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Get the set of RecordIDs that already have a RecordGeoCode row for an entity.
|
|
381
|
+
*/
|
|
382
|
+
async getExistingGeoCodeRecordIds(entityId, contextUser) {
|
|
383
|
+
const rv = new RunView();
|
|
384
|
+
const existingResult = await rv.RunView({
|
|
385
|
+
EntityName: 'MJ: Record Geo Codes',
|
|
386
|
+
ExtraFilter: `EntityID = '${entityId}'`,
|
|
387
|
+
Fields: ['RecordID'],
|
|
388
|
+
ResultType: 'simple',
|
|
389
|
+
IgnoreMaxRows: true
|
|
390
|
+
}, contextUser);
|
|
391
|
+
return new Set(existingResult.Success ? existingResult.Results.map(r => r.RecordID) : []);
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Build a RecordID string from an entity's primary key, matching the
|
|
395
|
+
* format used in the view's LEFT JOIN to RecordGeoCode.
|
|
396
|
+
*/
|
|
397
|
+
buildRecordId(entity) {
|
|
398
|
+
const pkPairs = entity.PrimaryKey.KeyValuePairs;
|
|
399
|
+
return pkPairs.length === 1
|
|
400
|
+
? String(pkPairs[0].Value)
|
|
401
|
+
: pkPairs.map(pk => String(pk.Value)).join('||');
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Extract a numeric parameter with a default value.
|
|
405
|
+
*/
|
|
406
|
+
getNumericParam(params, name, defaultValue) {
|
|
407
|
+
const param = params.Params.find(p => p.Name.trim().toLowerCase() === name.toLowerCase());
|
|
408
|
+
if (!param || param.Value === undefined || param.Value === null)
|
|
409
|
+
return defaultValue;
|
|
410
|
+
const parsed = Number(param.Value);
|
|
411
|
+
return isNaN(parsed) ? defaultValue : parsed;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Extract an optional numeric parameter. Returns null if not provided.
|
|
415
|
+
*/
|
|
416
|
+
getNullableNumericParam(params, name) {
|
|
417
|
+
const param = params.Params.find(p => p.Name.trim().toLowerCase() === name.toLowerCase());
|
|
418
|
+
if (!param || param.Value === undefined || param.Value === null)
|
|
419
|
+
return null;
|
|
420
|
+
const parsed = Number(param.Value);
|
|
421
|
+
return isNaN(parsed) ? null : parsed;
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
ScheduledGeocodingAction = ScheduledGeocodingAction_1 = __decorate([
|
|
425
|
+
RegisterClass(BaseAction, 'Scheduled Geocoding')
|
|
426
|
+
], ScheduledGeocodingAction);
|
|
427
|
+
export { ScheduledGeocodingAction };
|
|
428
|
+
//# sourceMappingURL=scheduled-geocoding.action.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-geocoding.action.js","sourceRoot":"","sources":["../../../src/custom/geo/scheduled-geocoding.action.ts"],"names":[],"mappings":";;;;;;;AACA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EACH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EACtC,YAAY,EAAE,UAAU,EAAE,eAAe,EAC5C,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEI,IAAM,wBAAwB,GAA9B,MAAM,wBAAyB,SAAQ,UAAU;;aAC5B,wBAAmB,GAAG,CAAC,AAAJ,CAAK;aACxB,uBAAkB,GAAG,EAAE,AAAL,CAAM;IAEtC,KAAK,CAAC,iBAAiB,CAAC,MAAuB;QACrD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,kDAAkD,EAAE,CAAC;QACvH,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,0BAAwB,CAAC,mBAAmB,CAAC,CAAC;QAC5G,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,0BAAwB,CAAC,kBAAkB,CAAC,CAAC;QACzG,MAAM,QAAQ,GAAG,IAAI,CAAC,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;QAEzE,SAAS,CAAC,iEAAiE,SAAS,cAAc,QAAQ,IAAI,WAAW,GAAG,CAAC,CAAC;QAE9H,MAAM,KAAK,GAAG,EAAE,gBAAgB,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC;QAEpH,2CAA2C;QAC3C,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QACxF,KAAK,CAAC,gBAAgB,GAAG,YAAY,CAAC,SAAS,CAAC;QAChD,KAAK,CAAC,cAAc,GAAG,YAAY,CAAC,OAAO,CAAC;QAE5C,0CAA0C;QAC1C,MAAM,aAAa,GAAG,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/F,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;QACtG,KAAK,CAAC,gBAAgB,GAAG,UAAU,CAAC,SAAS,CAAC;QAC9C,KAAK,CAAC,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC;QAE1C,+CAA+C;QAC/C,KAAK,CAAC,cAAc,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAEjF,SAAS,CAAC,iDAAiD,KAAK,CAAC,gBAAgB,eAAe,KAAK,CAAC,cAAc,uBAAuB,KAAK,CAAC,gBAAgB,KAAK,KAAK,CAAC,cAAc,uBAAuB,KAAK,CAAC,cAAc,UAAU,CAAC,CAAC;QAEjP,OAAO;YACH,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,SAAS;YACrB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SACjC,CAAC;IACN,CAAC;IAED,mEAAmE;IACnE,6CAA6C;IAC7C,mEAAmE;IAEnE;;;;OAIG;IACK,KAAK,CAAC,qBAAqB,CAC/B,WAAqB,EACrB,SAAiB,EACjB,QAAuB;QAEvB,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACjE,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACnC,IAAI,QAAQ,IAAI,IAAI,IAAI,cAAc,IAAI,QAAQ;gBAAE,MAAM;YAE1D,MAAM,SAAS,GAAG,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;YACtE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;YACtG,cAAc,IAAI,WAAW,CAAC,SAAS,CAAC;YACxC,YAAY,IAAI,WAAW,CAAC,OAAO,CAAC;QACxC,CAAC;QAED,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,uCAAuC,cAAc,qBAAqB,YAAY,yBAAyB,CAAC,CAAC;QAC/H,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IAChE,CAAC;IAED;;;;;;;;;;OAUG;IACK,KAAK,CAAC,uBAAuB,CACjC,UAAsB,EACtB,WAAqB,EACrB,SAAiB,EACjB,OAAsB;QAEtB,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,CAAC;QAC3C,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QAElD,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QAEhE,IAAI,CAAC;YACD,2DAA2D;YAC3D,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,2BAA2B,CAAC,UAAU,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;YAE7F,+CAA+C;YAC/C,MAAM,iBAAiB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnF,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;gBAC5B,UAAU,EAAE,UAAU,CAAC,IAAI;gBAC3B,WAAW,EAAE,IAAI,iBAAiB,GAAG;gBACrC,aAAa,EAAE,IAAI;gBACnB,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,eAAe;aAC9B,EAAE,WAAW,CAAC,CAAC;YAEhB,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjD,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACxC,CAAC;YAED,qCAAqC;YACrC,IAAI,cAAc,GAAI,MAAM,CAAC,OAAmC;iBAC3D,MAAM,CAAC,MAAM,CAAC,EAAE;gBACb,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;gBAC5C,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5C,CAAC,CAAC,CAAC;YAEP,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;gBAClB,cAAc,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACtD,CAAC;YAED,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YAErE,8BAA8B;YAC9B,OAAO,MAAM,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;QACvF,CAAC;QAAC,OAAO,CAAU,EAAE,CAAC;YAClB,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACvD,QAAQ,CAAC,gEAAgE,UAAU,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC,CAAC;YACpG,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QACxC,CAAC;IACL,CAAC;IAED,mEAAmE;IACnE,0CAA0C;IAC1C,mEAAmE;IAEnE;;;;OAIG;IACK,KAAK,CAAC,oBAAoB,CAC9B,WAAqB,EACrB,UAAkB,EAClB,SAAiB,EACjB,QAAuB;QAEvB,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;QAEzB,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,OAAO,CAAwB;YACzD,UAAU,EAAE,sBAAsB;YAClC,WAAW,EAAE,oCAAoC,UAAU,EAAE;YAC7D,aAAa,EAAE,IAAI;YACnB,OAAO,EAAE,gCAAgC;YACzC,UAAU,EAAE,eAAe;SAC9B,EAAE,WAAW,CAAC,CAAC;QAEhB,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7D,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QACxC,CAAC;QAED,IAAI,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;QACnC,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACnB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACzC,CAAC;QAED,SAAS,CAAC,6BAA6B,OAAO,CAAC,MAAM,oCAAoC,CAAC,CAAC;QAE3F,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,2CAA2C;QAC3C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmC,CAAC;QAC5D,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC;YAC/B,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACP,GAAG,GAAG,EAAE,CAAC;gBACT,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC3B,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;QAED,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,QAAQ,EAAE,CAAC;YAC5C,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC3C,IAAI,CAAC,UAAU;gBAAE,SAAS;YAE1B,kEAAkE;YAClE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;YACpF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAEpC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;YACpF,cAAc,IAAI,KAAK,CAAC,SAAS,CAAC;YAClC,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC;QAClC,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IAChE,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,kBAAkB,CAC5B,UAAmC,EACnC,UAAsB,EACtB,WAAqB;QAErB,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAiB,EAAE,CAAC;QAElC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACjC,IAAI,CAAC;gBACD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;gBACtE,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;gBAC9E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBAC1C,IAAI,MAAM,EAAE,CAAC;oBACT,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC1B,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACL,wDAAwD;YAC5D,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,mEAAmE;IACnE,yBAAyB;IACzB,mEAAmE;IAEnE;;;OAGG;IACK,KAAK,CAAC,sBAAsB,CAChC,WAAqB,EACrB,SAAiB;QAEjB,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,4CAA4C;QAC5C,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,OAAO,CAAuB;YACxD,UAAU,EAAE,sBAAsB;YAClC,MAAM,EAAE,CAAC,UAAU,CAAC;YACpB,UAAU,EAAE,QAAQ;YACpB,aAAa,EAAE,IAAI;SACtB,EAAE,WAAW,CAAC,CAAC;QAEhB,IAAI,CAAC,YAAY,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC;QAEpC,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAE1E,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACD,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBAC3C,IAAI,CAAC,UAAU;oBAAE,SAAS;gBAE1B,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,CAAC;gBAC3C,IAAI,CAAC,OAAO;oBAAE,SAAS;gBAEvB,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,OAAO,CAAwB;oBACzD,UAAU,EAAE,sBAAsB;oBAClC,WAAW,EAAE,eAAe,QAAQ,mCAAmC,UAAU,CAAC,UAAU,IAAI,UAAU,CAAC,SAAS,uBAAuB,OAAO,CAAC,IAAI,gCAAgC;oBACvL,aAAa,EAAE,IAAI;oBACnB,UAAU,EAAE,eAAe;iBAC9B,EAAE,WAAW,CAAC,CAAC;gBAEhB,IAAI,YAAY,CAAC,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1D,qCAAqC;oBACrC,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;oBACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;wBACjD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;wBAC9C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;wBACrE,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;oBACpF,CAAC;oBACD,SAAS,CAAC,qCAAqC,YAAY,CAAC,OAAO,CAAC,MAAM,6BAA6B,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC9H,CAAC;YACL,CAAC;YAAC,OAAO,CAAU,EAAE,CAAC;gBAClB,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACvD,QAAQ,CAAC,6DAA6D,QAAQ,KAAK,GAAG,EAAE,CAAC,CAAC;YAC9F,CAAC;QACL,CAAC;QAED,OAAO,YAAY,CAAC;IACxB,CAAC;IAED,mEAAmE;IACnE,yDAAyD;IACzD,mEAAmE;IAEnE;;;;;;;;;;;;;;OAcG;IACK,KAAK,CAAC,YAAY,CACtB,QAAsB,EACtB,UAAsB,EACtB,WAAqB,EACrB,SAAiB;QAEjB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;YAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;YAE/C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACpC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CACtE,CAAC;YAEF,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;YACrF,YAAY,IAAI,YAAY,CAAC;YAE7B,IAAI,QAAQ,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;gBAC9B,SAAS,CAAC,6BAA6B,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,YAAY,IAAI,KAAK,CAAC,MAAM,UAAU,CAAC,CAAC;YACzL,CAAC;QACL,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IACjE,CAAC;IAED;;;;;;;;;;OAUG;IACK,KAAK,CAAC,oBAAoB,CAAC,MAAkB,EAAE,WAAqB;QACxE,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAEpF,IAAI,MAAM,EAAE,CAAC;gBACT,gEAAgE;gBAChE,mEAAmE;gBACnE,qEAAqE;gBACrE,mEAAmE;gBACnE,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC1C,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;YACxC,CAAC;YAED,OAAO,IAAI,CAAC;QAChB,CAAC;QAAC,OAAO,CAAU,EAAE,CAAC;YAClB,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACvD,QAAQ,CAAC,+CAA+C,MAAM,CAAC,UAAU,CAAC,IAAI,YAAY,GAAG,EAAE,CAAC,CAAC;YACjG,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED;;;;;;;;;;;OAWG;IACK,sBAAsB,CAAC,MAAkB;QAC7C,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC;QACpB,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC;QAC7B,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC;QAC1B,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;QAErB,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;YACzB,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,WAAW,CAAC,cAAc;YACjC,SAAS,EAAE,UAAU,CAAC,aAAa;YACnC,IAAI,EAAE,KAAK;SACd,CAAC,CAAC;IACP,CAAC;IAED,mEAAmE;IACnE,UAAU;IACV,mEAAmE;IAEnE;;;;OAIG;IACK,mBAAmB,CAAC,UAAsB;QAC9C,OAAO,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAChC,CAAC,CAAC,YAAY,IAAI,IAAI,IAAI,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC;YAC1D,CAAC,CAAC,YAAY,KAAK,aAAa,IAAI,CAAC,CAAC,YAAY,KAAK,cAAc,CACxE,CAAC;IACN,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,2BAA2B,CAAC,QAAgB,EAAE,WAAqB;QAC7E,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,OAAO,CAAuB;YAC1D,UAAU,EAAE,sBAAsB;YAClC,WAAW,EAAE,eAAe,QAAQ,GAAG;YACvC,MAAM,EAAE,CAAC,UAAU,CAAC;YACpB,UAAU,EAAE,QAAQ;YACpB,aAAa,EAAE,IAAI;SACtB,EAAE,WAAW,CAAC,CAAC;QAEhB,OAAO,IAAI,GAAG,CACV,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAC5E,CAAC;IACN,CAAC;IAED;;;OAGG;IACK,aAAa,CAAC,MAAkB;QACpC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC;QAChD,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC;YACvB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YAC1B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,MAAuB,EAAE,IAAY,EAAE,YAAoB;QAC/E,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1F,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO,YAAY,CAAC;QACrF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;IACjD,CAAC;IAED;;OAEG;IACK,uBAAuB,CAAC,MAAuB,EAAE,IAAY;QACjE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1F,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC7E,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IACzC,CAAC;;AAjdQ,wBAAwB;IADpC,aAAa,CAAC,UAAU,EAAE,qBAAqB,CAAC;GACpC,wBAAwB,CAkdpC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ActionResultSimple, RunActionParams } from "@memberjunction/actions-base";
|
|
2
|
+
import { BaseAction } from "@memberjunction/actions";
|
|
3
|
+
/**
|
|
4
|
+
* Action that executes a universal search across the organization's knowledge base.
|
|
5
|
+
*
|
|
6
|
+
* This action delegates to the `@memberjunction/search-engine` singleton which
|
|
7
|
+
* orchestrates vector similarity search, full-text search, entity LIKE-based search,
|
|
8
|
+
* and (optionally) storage file search. Results are fused via Reciprocal Rank Fusion (RRF),
|
|
9
|
+
* deduplicated, and enriched with entity icons, record names, and tags.
|
|
10
|
+
*
|
|
11
|
+
* Designed for use by AI agents (Sage, etc.), MCP connectors, A2A connectors,
|
|
12
|
+
* and workflow orchestration.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Simple search
|
|
17
|
+
* await runAction({
|
|
18
|
+
* ActionName: 'Search',
|
|
19
|
+
* Params: [{ Name: 'Query', Value: 'quarterly revenue by region' }]
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Advanced search with filters
|
|
23
|
+
* await runAction({
|
|
24
|
+
* ActionName: 'Search',
|
|
25
|
+
* Params: [
|
|
26
|
+
* { Name: 'Query', Value: 'customer onboarding process' },
|
|
27
|
+
* { Name: 'MaxResults', Value: 10 },
|
|
28
|
+
* { Name: 'MinScore', Value: 0.3 },
|
|
29
|
+
* { Name: 'EntityNames', Value: 'Documents,Knowledge Articles' },
|
|
30
|
+
* { Name: 'IncludeSources', Value: 'vector,fulltext' }
|
|
31
|
+
* ]
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class SearchAction extends BaseAction {
|
|
36
|
+
protected InternalRunAction(params: RunActionParams): Promise<ActionResultSimple>;
|
|
37
|
+
/**
|
|
38
|
+
* Parse the IncludeSources parameter into a SearchSource array.
|
|
39
|
+
* Accepts a comma-separated string.
|
|
40
|
+
*/
|
|
41
|
+
private parseIncludeSources;
|
|
42
|
+
/**
|
|
43
|
+
* Parse the EntityNames filter parameter into a string array.
|
|
44
|
+
*/
|
|
45
|
+
private parseEntityNames;
|
|
46
|
+
/**
|
|
47
|
+
* Parse the Tags filter parameter into a string array.
|
|
48
|
+
*/
|
|
49
|
+
private parseTags;
|
|
50
|
+
/**
|
|
51
|
+
* Build a SearchParams object from the extracted and validated parameters.
|
|
52
|
+
*/
|
|
53
|
+
private buildSearchParams;
|
|
54
|
+
/**
|
|
55
|
+
* Build a SearchFilters object from the parsed filter parameters.
|
|
56
|
+
* Returns undefined if no filters are specified.
|
|
57
|
+
*/
|
|
58
|
+
private buildFilters;
|
|
59
|
+
/**
|
|
60
|
+
* Convert SearchResultItem objects into serialization-safe formatted results.
|
|
61
|
+
*/
|
|
62
|
+
private formatResults;
|
|
63
|
+
private getStringParam;
|
|
64
|
+
private getNumericParam;
|
|
65
|
+
private createErrorResult;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=search.action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.action.d.ts","sourceRoot":"","sources":["../../../src/custom/search/search.action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAe,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAkCrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBACa,YAAa,SAAQ,UAAU;cAExB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAiEvF;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAW3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;OAEG;IACH,OAAO,CAAC,SAAS;IAMjB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsBzB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAsBpB;;OAEG;IACH,OAAO,CAAC,aAAa;IA0BrB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,iBAAiB;CAO5B"}
|