@skedulo/pulse-solution-services 0.0.8 → 0.0.9

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.0.9] - 2025-02-28
4
+ ### Added
5
+ - Lock Service, Unique Batch
6
+
3
7
  ## [v0.0.8] - 2025-02-17
4
8
  ### Added
5
9
  - GraphBatch
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  - [Config Features (Feature Flags) Client](#config-features-feature-flags-client)
14
14
  - [Mobile Notification Client](#mobile-notification-client)
15
15
  - [Configuration Templates](#configuration-templates)
16
- - [Geoservices Client](#geoservices-client)
16
+ - [Geo API Client](#geo-api-client)
17
17
  - [Artifact Client](#artifact-client)
18
18
  - [GraphQL Service](#graphql-service)
19
19
  - [Query Data](#query-data)
@@ -25,6 +25,7 @@
25
25
  - [Resource Validator](#resource-validator)
26
26
  - [GeoService](#geoservice)
27
27
  - [Batch Service](#batch-service)
28
+ - [Lock Service](#lock-service)
28
29
  - [Cache Service](#cache-service)
29
30
  - [Logging Utils](#logging-utils)
30
31
 
@@ -47,10 +48,10 @@ yarn add @skedulo/pulse-solution-services
47
48
 
48
49
  **From a function**
49
50
  ```javascript
50
- const context = ExecutionContext.fromContext(skedToken, {
51
+ const context = ExecutionContext.fromContext(skedContext, {
51
52
  requestSource: "my-cool-project",
52
53
  userAgent: "my-cool-function"
53
- } as ExecutionOptions);
54
+ });
54
55
  ```
55
56
 
56
57
  The `requestSource` and `userAgent` options are important for observability and debugging, as they set the value for the `X-Skedulo-Source` and `User-Agent` headers that are automatically included in all requests made within this context.
@@ -63,7 +64,7 @@ const context = ExecutionContext.fromCredentials({
63
64
  }, {
64
65
  requestSource: "my-cool-project",
65
66
  userAgent: "my-cool-function"
66
- } as ExecutionOptions);
67
+ });
67
68
  ```
68
69
  Once initialized, the context object provides access to the various services detailed in subsequent sections.
69
70
  ### API Clients
@@ -108,7 +109,9 @@ const queryResult = await context.graphqlClient.execute(queryString, {readOnly:
108
109
  ```
109
110
 
110
111
  #### Config Variable Client
112
+
111
113
  Provides CRUD and search methods for managing configuration variables.
114
+
112
115
  ```javascript
113
116
  // Calls /configuration/extension endpoint to create a configuration var
114
117
  await context.configVarClient.create({
@@ -117,8 +120,12 @@ await context.configVarClient.create({
117
120
  configType: "plain-text",
118
121
  description: "TEST_DESCRIPTION",
119
122
  });
123
+
120
124
  // Gets a config var
121
125
  const config = await context.configVarClient.get('TEST_KEY');
126
+
127
+ // Deletes a config var
128
+ const config = await context.configVarClient.delete('TEST_KEY');
122
129
  ```
123
130
 
124
131
  #### Org Preferences Client
@@ -601,6 +608,19 @@ if (suggestions) {
601
608
  }
602
609
  ```
603
610
 
611
+ ### Lock Service
612
+ The Lock Service provides a locking mechanism to prevent concurrent execution of critical processes, such as batch jobs. It ensures that only one instance of a process can proceed at a time by using configuration variables with expiration timestamps.
613
+ ```javascript
614
+ // Acquire a lock, auto release after 5 minutes
615
+ const lockAcquired = await context.lockService.acquireLock({
616
+ name: 'MY_LOCK',
617
+ ttl: 5 * 60 * 1000, // 5 minutes
618
+ });
619
+
620
+ // Release a lock
621
+ await context.lockService.releaseLock('MY_LOCK');
622
+ ```
623
+
604
624
  ### Batch Service
605
625
  The Batch Service offers a flexible and scalable solution for large-scale data processing.
606
626
 
@@ -672,6 +692,29 @@ const batch = new BulkJobUpdate(context, {
672
692
  await batch.run();
673
693
  ```
674
694
 
695
+ #### Unique Batch
696
+ The Unique Batch ensures that only one instance runs at a time. It leverages the Lock Service to prevent concurrent executions. The default lock duration is 16 minutes, configurable via the `lockTtl` setting.
697
+
698
+ **Implementation**
699
+
700
+ To create a unique batch, extend the `UniqueGraphBatch` class, everything else remains the same as a regular `GraphBatch`.
701
+
702
+ ```javascript
703
+ export class UniqueBulkJobUpdate extends UniqueGraphBatch {
704
+ ```
705
+ **Run a unique batch**
706
+ ```javascript
707
+ const batch = new UniqueBulkJobUpdate(context, {
708
+ batchSize: 10,
709
+ maxBatches: 10,
710
+ strategy: PaginationStrategy.CURSOR,
711
+ delaySeconds: 1,
712
+ lockTtl: 5 * 60 * 1000, // 5 minutes - optional
713
+ });
714
+ batch.run(); // Runs successfully
715
+ batch.run(); // Fails (lock still active)
716
+ ```
717
+
675
718
  ### Cache Service
676
719
  The Cache Service enables efficient data sharing between function executions and improves performance by reducing redundant operations and API calls.
677
720
  ```javascript
@@ -1 +1 @@
1
- "use strict";var __awaiter=this&&this.__awaiter||function(t,e,n,i){return new(n||(n=Promise))((function(o,r){function s(t){try{d(i.next(t))}catch(t){r(t)}}function a(t){try{d(i.throw(t))}catch(t){r(t)}}function d(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(s,a)}d((i=i.apply(t,e||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.ConfigVarClient=void 0;const constants_1=require("../constants"),base_client_1=require("./base-client");class ConfigVarClient extends base_client_1.BaseClient{create(t){return __awaiter(this,void 0,void 0,(function*(){return yield this.performRequest({method:constants_1.HttpMethod.POST,endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.CREATE,body:t})}))}get(t){return __awaiter(this,void 0,void 0,(function*(){return yield this.performRequest({endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.GET(t)})}))}update(t){return __awaiter(this,void 0,void 0,(function*(){const e=t.key||"";return delete t.key,yield this.performRequest({method:constants_1.HttpMethod.PATCH,endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.UPDATE(e),body:{value:t.value,description:t.description}})}))}search(t){return __awaiter(this,void 0,void 0,(function*(){return yield this.performRequest({method:constants_1.HttpMethod.POST,endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.SEARCH,body:{pageSize:t&&t<1e3?t:1e3}})}))}delete(t){return __awaiter(this,void 0,void 0,(function*(){return yield this.performRequest({method:constants_1.HttpMethod.DELETE,endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.DELETE(t)})}))}}exports.ConfigVarClient=ConfigVarClient;
1
+ "use strict";var __awaiter=this&&this.__awaiter||function(t,e,n,i){return new(n||(n=Promise))((function(o,r){function s(t){try{d(i.next(t))}catch(t){r(t)}}function a(t){try{d(i.throw(t))}catch(t){r(t)}}function d(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(s,a)}d((i=i.apply(t,e||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.ConfigVarClient=void 0;const constants_1=require("../constants"),base_client_1=require("./base-client");class ConfigVarClient extends base_client_1.BaseClient{create(t){return __awaiter(this,void 0,void 0,(function*(){return yield this.performRequest({method:constants_1.HttpMethod.POST,endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.CREATE,body:t})}))}get(t){return __awaiter(this,void 0,void 0,(function*(){return yield this.performRequest({endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.GET(t)})}))}update(t){return __awaiter(this,void 0,void 0,(function*(){const e=t.key||"";delete t.key;const n={};return void 0!==t.value&&(n.value=t.value),void 0!==t.description&&(n.description=t.description),void 0!==t.expiryDate&&(n.expiryDate=t.expiryDate),void 0!==t.status&&(n.status=t.status),yield this.performRequest({method:constants_1.HttpMethod.PATCH,endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.UPDATE(e),body:n})}))}upsert(t){return __awaiter(this,void 0,void 0,(function*(){try{return yield this.update(Object.assign({},t))}catch(e){return yield this.create(t)}}))}search(t){return __awaiter(this,void 0,void 0,(function*(){return yield this.performRequest({method:constants_1.HttpMethod.POST,endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.SEARCH,body:{pageSize:t&&t<1e3?t:1e3}})}))}delete(t){return __awaiter(this,void 0,void 0,(function*(){return yield this.performRequest({method:constants_1.HttpMethod.DELETE,endpoint:constants_1.TENANT_ENDPOINTS.CONFIG_VAR.DELETE(t)})}))}}exports.ConfigVarClient=ConfigVarClient;
@@ -1 +1 @@
1
- "use strict";var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.ExecutionContext=void 0;const function_utilities_1=require("@skedulo/function-utilities"),clients_1=require("../clients"),artifact_client_1=require("../clients/artifact-client"),availability_api_client_1=require("../clients/availability-api-client"),config_features_client_1=require("../clients/config-features-client"),config_template_client_1=require("../clients/config-template-client"),config_var_client_1=require("../clients/config-var-client"),geo_api_client_1=require("../clients/geo-api-client"),graphql_client_1=require("../clients/graphql-client"),metadata_client_1=require("../clients/metadata-client"),mobile_notification_client_1=require("../clients/mobile-notification-client"),org_preference_client_1=require("../clients/org-preference-client"),vocabulary_client_1=require("../clients/vocabulary-client"),logger_1=__importDefault(require("../logging/logger")),cache_service_1=require("../services/cache/cache-service"),storage_1=require("../services/cache/storage"),geoservice_1=require("../services/geoservice"),graphql_1=require("../services/graphql"),metadata_service_1=require("../services/metadata-service"),data_service_1=require("../services/resource-availability/builder/data-service"),resource_availability_service_1=require("../services/resource-availability/builder/resource-availability-service"),resource_builder_1=require("../services/resource-availability/builder/resource-builder"),utils_1=require("../utils"),request_header_constants_1=require("./request-header-constants");class ExecutionContext{constructor(e,i={}){this.logger=logger_1.default,this.services=new Map,this.skedContext=e,this.contextData={},this._executionOptions=i,this.baseConfig={apiToken:e.auth.token,apiServer:e.auth.baseUrl}}static fromContext(e,i={}){return new ExecutionContext(e,i)}static fromCredentials(e,i={}){const t={Authorization:`Bearer ${e.apiToken}`,[request_header_constants_1.REQUEST_HEADERS.SKED_API_SERVER]:e.apiServer},r=(0,function_utilities_1.createSkedContext)(t),n=new ExecutionContext(r,i);return n.baseConfig=Object.assign(Object.assign({},e),n.baseConfig),n}set executionOptions(e){this._executionOptions=Object.assign(Object.assign({},this._executionOptions),e)}get executionOptions(){return this._executionOptions}getOrCreateService(e,i){return this.services.has(e)||this.services.set(e,i()),this.services.get(e)}get configHelper(){return this.getOrCreateService("configHelper",(()=>new utils_1.ConfigHelper(this.skedContext.configVars)))}get baseClient(){return this.getOrCreateService("baseClient",(()=>new clients_1.BaseClient(this.baseConfig,this.executionOptions)))}get graphqlClient(){return this.getOrCreateService("graphqlClient",(()=>new graphql_client_1.GraphQLClient(this.baseConfig,this.executionOptions)))}get graphqlService(){return this.getOrCreateService("graphqlService",(()=>new graphql_1.GraphQLService(this.graphqlClient)))}get metadataClient(){return this.getOrCreateService("metadataClient",(()=>new metadata_client_1.MetadataClient(this.baseConfig,this.executionOptions)))}get metadataService(){return this.getOrCreateService("metadataService",(()=>new metadata_service_1.MetadataService(this.metadataClient)))}get vocabularyClient(){return this.getOrCreateService("vocabularyClient",(()=>new vocabulary_client_1.VocabularyClient(this.baseConfig,this.executionOptions)))}get orgPreferencesClient(){return this.getOrCreateService("orgPreferencesClient",(()=>new org_preference_client_1.OrgPreferenceClient(this.baseConfig,this.executionOptions)))}get configTemplateClient(){return this.getOrCreateService("configTemplateClient",(()=>new config_template_client_1.ConfigTemplateClient(this.baseConfig,this.executionOptions)))}get configFeaturesClient(){return this.getOrCreateService("configFeaturesClient",(()=>new config_features_client_1.ConfigFeaturesClient(this.baseConfig,this.executionOptions)))}get configVarClient(){return this.getOrCreateService("configVarClient",(()=>new config_var_client_1.ConfigVarClient(this.baseConfig,this.executionOptions)))}get mobileNotificationClient(){return this.getOrCreateService("mobileNotificationClient",(()=>new mobile_notification_client_1.MobileNotificationClient(this.baseConfig,this.executionOptions)))}get geoAPIClient(){return this.getOrCreateService("geoAPIClient",(()=>new geo_api_client_1.GeoAPIClient(this.baseConfig,this.executionOptions)))}get availabilityAPIClient(){return this.getOrCreateService("availabilityAPIClient",(()=>new availability_api_client_1.AvailabilityAPIClient(this.baseConfig,this.executionOptions)))}get geoService(){return this.getOrCreateService("geoService",(()=>new geoservice_1.GeoService(this.geoAPIClient)))}get configVarCache(){return this.getOrCreateService("configVarCache",(()=>new cache_service_1.CacheService(new storage_1.ConfigVarCacheStorage(this.configVarClient))))}get inMemoryCache(){return this.getOrCreateService("inMemoryCache",(()=>{const e=new cache_service_1.CacheService(new storage_1.InMemoryCacheStorage);return e.setSecondaryCache(this.configVarCache),e}))}get resourceAvailabilityService(){return this.getOrCreateService("resourceAvailabilityService",(()=>new resource_availability_service_1.ResourceAvailabilityService(this.availabilityAPIClient)))}get dataService(){return this.getOrCreateService("dataService",(()=>new data_service_1.DataService(this.graphqlService)))}get resourceBuilder(){return this.getOrCreateService("resourceBuilder",(()=>new resource_builder_1.ResourceBuilder(this.dataService,this.resourceAvailabilityService)))}newQueryBuilder(e){const i=new graphql_1.GraphQLQueryBuilder(e);return i.setGraphqlService(this.graphqlService),i}newArtifactClient(e){return this.getOrCreateService(`${e}Client`,(()=>new artifact_client_1.ArtifactClient(this.baseConfig,e,this.executionOptions)))}dispose(){this.services.clear()}}exports.ExecutionContext=ExecutionContext;
1
+ "use strict";var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.ExecutionContext=void 0;const function_utilities_1=require("@skedulo/function-utilities"),clients_1=require("../clients"),artifact_client_1=require("../clients/artifact-client"),availability_api_client_1=require("../clients/availability-api-client"),config_features_client_1=require("../clients/config-features-client"),config_template_client_1=require("../clients/config-template-client"),config_var_client_1=require("../clients/config-var-client"),geo_api_client_1=require("../clients/geo-api-client"),graphql_client_1=require("../clients/graphql-client"),metadata_client_1=require("../clients/metadata-client"),mobile_notification_client_1=require("../clients/mobile-notification-client"),org_preference_client_1=require("../clients/org-preference-client"),vocabulary_client_1=require("../clients/vocabulary-client"),logger_1=__importDefault(require("../logging/logger")),cache_service_1=require("../services/cache/cache-service"),storage_1=require("../services/cache/storage"),geoservice_1=require("../services/geoservice"),graphql_1=require("../services/graphql"),lock_service_1=require("../services/lock-service"),metadata_service_1=require("../services/metadata-service"),data_service_1=require("../services/resource-availability/builder/data-service"),resource_availability_service_1=require("../services/resource-availability/builder/resource-availability-service"),resource_builder_1=require("../services/resource-availability/builder/resource-builder"),utils_1=require("../utils"),request_header_constants_1=require("./request-header-constants");class ExecutionContext{constructor(e,i={}){this.logger=logger_1.default,this.services=new Map,this.skedContext=e,this.contextData={},this._executionOptions=i,this.baseConfig={apiToken:e.auth.token,apiServer:e.auth.baseUrl}}static fromContext(e,i={}){return new ExecutionContext(e,i)}static fromCredentials(e,i={}){const t={Authorization:`Bearer ${e.apiToken}`,[request_header_constants_1.REQUEST_HEADERS.SKED_API_SERVER]:e.apiServer},r=(0,function_utilities_1.createSkedContext)(t),n=new ExecutionContext(r,i);return n.baseConfig=Object.assign(Object.assign({},e),n.baseConfig),n}set executionOptions(e){this._executionOptions=Object.assign(Object.assign({},this._executionOptions),e)}get executionOptions(){return this._executionOptions}getOrCreateService(e,i){return this.services.has(e)||this.services.set(e,i()),this.services.get(e)}get configHelper(){return this.getOrCreateService("configHelper",(()=>new utils_1.ConfigHelper(this.skedContext.configVars)))}get baseClient(){return this.getOrCreateService("baseClient",(()=>new clients_1.BaseClient(this.baseConfig,this.executionOptions)))}get graphqlClient(){return this.getOrCreateService("graphqlClient",(()=>new graphql_client_1.GraphQLClient(this.baseConfig,this.executionOptions)))}get graphqlService(){return this.getOrCreateService("graphqlService",(()=>new graphql_1.GraphQLService(this.graphqlClient)))}get metadataClient(){return this.getOrCreateService("metadataClient",(()=>new metadata_client_1.MetadataClient(this.baseConfig,this.executionOptions)))}get metadataService(){return this.getOrCreateService("metadataService",(()=>new metadata_service_1.MetadataService(this.metadataClient)))}get vocabularyClient(){return this.getOrCreateService("vocabularyClient",(()=>new vocabulary_client_1.VocabularyClient(this.baseConfig,this.executionOptions)))}get orgPreferencesClient(){return this.getOrCreateService("orgPreferencesClient",(()=>new org_preference_client_1.OrgPreferenceClient(this.baseConfig,this.executionOptions)))}get configTemplateClient(){return this.getOrCreateService("configTemplateClient",(()=>new config_template_client_1.ConfigTemplateClient(this.baseConfig,this.executionOptions)))}get configFeaturesClient(){return this.getOrCreateService("configFeaturesClient",(()=>new config_features_client_1.ConfigFeaturesClient(this.baseConfig,this.executionOptions)))}get configVarClient(){return this.getOrCreateService("configVarClient",(()=>new config_var_client_1.ConfigVarClient(this.baseConfig,this.executionOptions)))}get mobileNotificationClient(){return this.getOrCreateService("mobileNotificationClient",(()=>new mobile_notification_client_1.MobileNotificationClient(this.baseConfig,this.executionOptions)))}get geoAPIClient(){return this.getOrCreateService("geoAPIClient",(()=>new geo_api_client_1.GeoAPIClient(this.baseConfig,this.executionOptions)))}get availabilityAPIClient(){return this.getOrCreateService("availabilityAPIClient",(()=>new availability_api_client_1.AvailabilityAPIClient(this.baseConfig,this.executionOptions)))}get geoService(){return this.getOrCreateService("geoService",(()=>new geoservice_1.GeoService(this.geoAPIClient)))}get lockService(){return this.getOrCreateService("lockService",(()=>new lock_service_1.LockService(this.configVarClient)))}get configVarCache(){return this.getOrCreateService("configVarCache",(()=>new cache_service_1.CacheService(new storage_1.ConfigVarCacheStorage(this.configVarClient))))}get inMemoryCache(){return this.getOrCreateService("inMemoryCache",(()=>{const e=new cache_service_1.CacheService(new storage_1.InMemoryCacheStorage);return e.setSecondaryCache(this.configVarCache),e}))}get resourceAvailabilityService(){return this.getOrCreateService("resourceAvailabilityService",(()=>new resource_availability_service_1.ResourceAvailabilityService(this.availabilityAPIClient)))}get dataService(){return this.getOrCreateService("dataService",(()=>new data_service_1.DataService(this.graphqlService)))}get resourceBuilder(){return this.getOrCreateService("resourceBuilder",(()=>new resource_builder_1.ResourceBuilder(this.dataService,this.resourceAvailabilityService)))}newQueryBuilder(e){const i=new graphql_1.GraphQLQueryBuilder(e);return i.setGraphqlService(this.graphqlService),i}newArtifactClient(e){return this.getOrCreateService(`${e}Client`,(()=>new artifact_client_1.ArtifactClient(this.baseConfig,e,this.executionOptions)))}dispose(){this.services.clear()}}exports.ExecutionContext=ExecutionContext;
@@ -1 +1 @@
1
- "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r);var i=Object.getOwnPropertyDescriptor(t,r);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,i)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),__exportStar=this&&this.__exportStar||function(e,t){for(var r in e)"default"===r||Object.prototype.hasOwnProperty.call(t,r)||__createBinding(t,e,r)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("./entity-factory"),exports),__exportStar(require("./execution-context"),exports),__exportStar(require("./request-header-constants"),exports),__exportStar(require("./tenant-entities"),exports),__exportStar(require("./tenant-objects"),exports);
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r);var i=Object.getOwnPropertyDescriptor(t,r);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,i)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),__exportStar=this&&this.__exportStar||function(e,t){for(var r in e)"default"===r||Object.prototype.hasOwnProperty.call(t,r)||__createBinding(t,e,r)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("./entity-factory"),exports),__exportStar(require("./execution-context"),exports),__exportStar(require("./execution-options"),exports),__exportStar(require("./request-header-constants"),exports),__exportStar(require("./tenant-entities"),exports),__exportStar(require("./tenant-objects"),exports);
package/dist/index.d.ts CHANGED
@@ -57,7 +57,12 @@ export interface BaseConfig {
57
57
  apiToken: string;
58
58
  internalApiToken?: string;
59
59
  }
60
- declare class ExecutionOptions {
60
+ /**
61
+ * Represents execution options for GraphQL requests.
62
+ * This class encapsulates metadata and execution settings
63
+ * that enhance observability, performance, and request tracking.
64
+ */
65
+ export declare class ExecutionOptions {
61
66
  /**
62
67
  * Identifies the origin of the request (e.g., the system, application, or project that initiated the call).
63
68
  * Helps in tracking and debugging requests across different systems.
@@ -219,6 +224,7 @@ export interface ConfigVar {
219
224
  value: string;
220
225
  description?: string;
221
226
  status?: "active" | "inactive" | "expired";
227
+ expiryDate?: string;
222
228
  updatedBy?: string;
223
229
  createdBy?: string;
224
230
  createdAt?: string;
@@ -231,32 +237,26 @@ export interface ConfigVar {
231
237
  export declare class ConfigVarClient extends BaseClient {
232
238
  /**
233
239
  * Creates a new configuration variable.
234
- * @param {ConfigVar} configVar - The configuration variable to create.
235
- * @returns {Promise<ConfigVar>} - The created configuration variable.
236
240
  */
237
241
  create(configVar: ConfigVar): Promise<ConfigVar>;
238
242
  /**
239
243
  * Retrieves a configuration variable by key.
240
- * @param {string} key - The key of the configuration variable.
241
- * @returns {Promise<ConfigVar>} - The retrieved configuration variable.
242
244
  */
243
245
  get(key: string): Promise<ConfigVar>;
244
246
  /**
245
247
  * Updates an existing configuration variable.
246
- * @param {ConfigVar} configVar - The configuration variable with updated values. Only the value and description can be updated.
247
- * @returns {Promise<ConfigVar>} - A promise that resolves when the update is complete.
248
248
  */
249
249
  update(configVar: ConfigVar): Promise<ConfigVar>;
250
+ /**
251
+ * Upsert a configuration variable. If the configuration variable does not exist, it will be created.
252
+ */
253
+ upsert(configVar: ConfigVar): Promise<ConfigVar>;
250
254
  /**
251
255
  * Searches for configuration variables with pagination.
252
- * @param {number} [pageSize] - The number of results per page (default max is 1000).
253
- * @returns {Promise<ConfigVar[]>} - A list of configuration variables.
254
256
  */
255
257
  search(pageSize?: number): Promise<ConfigVar[]>;
256
258
  /**
257
259
  * Deletes a configuration variable by key.
258
- * @param {string} key - The key of the configuration variable to delete.
259
- * @returns {Promise<string>} - A response indicating the result of the delete operation.
260
260
  */
261
261
  delete(key: string): Promise<string>;
262
262
  }
@@ -856,6 +856,11 @@ declare class VocabularyClient extends BaseClient {
856
856
  */
857
857
  updateVocabularyItem(schemaName: string, fieldName: string, value: string, item: VocabularyItem): Promise<VocabularyItem>;
858
858
  }
859
+ export interface LockInfo {
860
+ name: string;
861
+ ttl: number;
862
+ description?: string;
863
+ }
859
864
  declare const logger: import("winston").Logger;
860
865
  export declare class CacheService<T> {
861
866
  private storage;
@@ -1091,6 +1096,12 @@ export declare class GraphQLQueryBuilder {
1091
1096
  */
1092
1097
  toString(): string;
1093
1098
  }
1099
+ declare class LockService {
1100
+ private configVarClient;
1101
+ constructor(configVarClient: ConfigVarClient);
1102
+ acquireLock(lockInfo: LockInfo): Promise<boolean>;
1103
+ releaseLock(name: string): Promise<void>;
1104
+ }
1094
1105
  export declare class ResourceQueryParam {
1095
1106
  resourceIds?: Set<string>;
1096
1107
  regionIds?: Set<string>;
@@ -1221,6 +1232,7 @@ export declare class ExecutionContext {
1221
1232
  get geoAPIClient(): GeoAPIClient;
1222
1233
  get availabilityAPIClient(): AvailabilityAPIClient;
1223
1234
  get geoService(): GeoService;
1235
+ get lockService(): LockService;
1224
1236
  get configVarCache(): CacheService<any>;
1225
1237
  get inMemoryCache(): CacheService<any>;
1226
1238
  get resourceAvailabilityService(): ResourceAvailabilityService;
@@ -1353,7 +1365,10 @@ export declare enum PaginationStrategy {
1353
1365
  * Default configuration values for `GraphBatchConfig`.
1354
1366
  */
1355
1367
  export declare const DEFAULT_GRAPH_BATCH_CONFIG: GraphBatchConfig;
1356
- declare const GraphBatchConfigSchema: z.ZodObject<{
1368
+ /**
1369
+ * Schema validation using `zod`
1370
+ */
1371
+ export declare const GraphBatchConfigSchema: z.ZodObject<{
1357
1372
  strategy: z.ZodNativeEnum<typeof PaginationStrategy>;
1358
1373
  batchSize: z.ZodDefault<z.ZodNumber>;
1359
1374
  maxBatches: z.ZodDefault<z.ZodNumber>;
@@ -1377,6 +1392,44 @@ export type GraphBatchConfig = z.infer<typeof GraphBatchConfigSchema>;
1377
1392
  * Merges user-provided config with default values.
1378
1393
  */
1379
1394
  export declare function initializeConfig(config: Partial<GraphBatchConfig> | undefined): GraphBatchConfig;
1395
+ /**
1396
+ * Default configuration values for `UniqueGraphBatchConfig`.
1397
+ */
1398
+ export declare const DEFAULT_UNIQUE_GRAPH_BATCH_CONFIG: UniqueGraphBatchConfig;
1399
+ /**
1400
+ * Schema validation for `UniqueGraphBatchConfig`
1401
+ */
1402
+ export declare const UniqueGraphBatchConfigSchema: z.ZodObject<z.objectUtil.extendShape<{
1403
+ strategy: z.ZodNativeEnum<typeof PaginationStrategy>;
1404
+ batchSize: z.ZodDefault<z.ZodNumber>;
1405
+ maxBatches: z.ZodDefault<z.ZodNumber>;
1406
+ delaySeconds: z.ZodDefault<z.ZodNumber>;
1407
+ }, {
1408
+ name: z.ZodOptional<z.ZodString>;
1409
+ lockTtl: z.ZodOptional<z.ZodNumber>;
1410
+ }>, "strip", z.ZodTypeAny, {
1411
+ strategy: PaginationStrategy;
1412
+ batchSize: number;
1413
+ maxBatches: number;
1414
+ delaySeconds: number;
1415
+ name?: string | undefined;
1416
+ lockTtl?: number | undefined;
1417
+ }, {
1418
+ strategy: PaginationStrategy;
1419
+ name?: string | undefined;
1420
+ batchSize?: number | undefined;
1421
+ maxBatches?: number | undefined;
1422
+ delaySeconds?: number | undefined;
1423
+ lockTtl?: number | undefined;
1424
+ }>;
1425
+ /**
1426
+ * Configuration options for `UniqueGraphBatch`.
1427
+ */
1428
+ export type UniqueGraphBatchConfig = z.infer<typeof UniqueGraphBatchConfigSchema>;
1429
+ /**
1430
+ * Merges user-provided config with default values for `UniqueGraphBatch`.
1431
+ */
1432
+ export declare function initializeUniqueConfig(config: Partial<UniqueGraphBatchConfig> | undefined): UniqueGraphBatchConfig;
1380
1433
  /**
1381
1434
  * Base class for batch processing with pagination support.
1382
1435
  */
@@ -1429,6 +1482,30 @@ export declare abstract class GraphBatch {
1429
1482
  */
1430
1483
  protected delay(ms: number): Promise<void>;
1431
1484
  }
1485
+ /**
1486
+ * UniqueGraphBatch ensures that only one instance of a batch with the same name can run at a time.
1487
+ */
1488
+ export declare class UniqueGraphBatch extends GraphBatch {
1489
+ private name;
1490
+ private lockTtl;
1491
+ constructor(context: ExecutionContext, config?: Partial<UniqueGraphBatchConfig>);
1492
+ /**
1493
+ * Runs the batch process with lock enforcement.
1494
+ */
1495
+ run(): Promise<void>;
1496
+ /**
1497
+ * Abstract method implementation - Initialize query builder.
1498
+ */
1499
+ protected start(): Promise<GraphQLQueryBuilder>;
1500
+ /**
1501
+ * Abstract method implementation - Process batch records.
1502
+ */
1503
+ protected execute(records: any[]): Promise<void>;
1504
+ /**
1505
+ * Overrides the finish method to ensure lock cleanup.
1506
+ */
1507
+ protected finish(): Promise<void>;
1508
+ }
1432
1509
  export interface ResourceValidationOption {
1433
1510
  checkAvailability: boolean;
1434
1511
  checkConflict: boolean;
@@ -1 +1 @@
1
- "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,r,t,i){void 0===i&&(i=t);var o=Object.getOwnPropertyDescriptor(r,t);o&&!("get"in o?!r.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return r[t]}}),Object.defineProperty(e,i,o)}:function(e,r,t,i){void 0===i&&(i=t),e[i]=r[t]}),__exportStar=this&&this.__exportStar||function(e,r){for(var t in e)"default"===t||Object.prototype.hasOwnProperty.call(r,t)||__createBinding(r,e,t)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("../core/tenant-entities"),exports),__exportStar(require("./api-client"),exports),__exportStar(require("./availability"),exports),__exportStar(require("./config-template"),exports),__exportStar(require("./config-var"),exports),__exportStar(require("./geoservice-interfaces"),exports),__exportStar(require("./graphql"),exports),__exportStar(require("./metadata"),exports),__exportStar(require("./mobile-notification"),exports);
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,r,t,i){void 0===i&&(i=t);var o=Object.getOwnPropertyDescriptor(r,t);o&&!("get"in o?!r.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return r[t]}}),Object.defineProperty(e,i,o)}:function(e,r,t,i){void 0===i&&(i=t),e[i]=r[t]}),__exportStar=this&&this.__exportStar||function(e,r){for(var t in e)"default"===t||Object.prototype.hasOwnProperty.call(r,t)||__createBinding(r,e,t)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("../core/tenant-entities"),exports),__exportStar(require("./api-client"),exports),__exportStar(require("./availability"),exports),__exportStar(require("./config-template"),exports),__exportStar(require("./config-var"),exports),__exportStar(require("./geoservice-interfaces"),exports),__exportStar(require("./graphql"),exports),__exportStar(require("./lock-service-interfaces"),exports),__exportStar(require("./metadata"),exports),__exportStar(require("./mobile-notification"),exports);
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});
@@ -1 +1 @@
1
- "use strict";var __decorate=this&&this.__decorate||function(e,t,a,r){var i,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,a):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,a,r);else for(var c=e.length-1;c>=0;c--)(i=e[c])&&(o=(n<3?i(o):n>3?i(t,a,o):i(t,a))||o);return n>3&&o&&Object.defineProperty(t,a,o),o},__metadata=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},__awaiter=this&&this.__awaiter||function(e,t,a,r){return new(a||(a=Promise))((function(i,n){function o(e){try{s(r.next(e))}catch(e){n(e)}}function c(e){try{s(r.throw(e))}catch(e){n(e)}}function s(e){var t;e.done?i(e.value):(t=e.value,t instanceof a?t:new a((function(e){e(t)}))).then(o,c)}s((r=r.apply(e,t||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.CacheService=void 0;const logging_1=require("../../logging"),KEY_PREFIX="Z_CACHE_",DEFAULT_TTL=36e5;class CacheService{constructor(e){this.storage=e}setSecondaryCache(e){this.secondaryCache=e}get(e,t){return __awaiter(this,void 0,void 0,(function*(){e=this.addPrefix(e);const a=yield this.storage.get(e);if(a)try{const t=JSON.parse(a);return t.expiresAt&&Date.now()>t.expiresAt?(yield this.delete(e),null):this.deserialize(t)}catch(e){return console.error("Cache deserialization failed:",e),null}if((null==t?void 0:t.useSecondaryCache)&&this.secondaryCache){const a=yield this.secondaryCache.get(e,t);return null!==a&&(yield this.set(e,a,{ttl:null==t?void 0:t.ttl})),a}return null}))}set(e,t,a){return __awaiter(this,void 0,void 0,(function*(){var r;e=this.addPrefix(e);const i={type:t instanceof Date?"date":typeof t,value:t,expiresAt:Date.now()+(null!==(r=null==a?void 0:a.ttl)&&void 0!==r?r:36e5)},n=JSON.stringify(i);yield this.storage.set(e,n),(null==a?void 0:a.useSecondaryCache)&&this.secondaryCache&&(yield this.secondaryCache.set(e,t,a))}))}delete(e){return __awaiter(this,void 0,void 0,(function*(){e=this.addPrefix(e),yield this.storage.delete(e)}))}clear(){return __awaiter(this,void 0,void 0,(function*(){yield this.storage.clear()}))}addPrefix(e){return e.startsWith("Z_CACHE_")?e:"Z_CACHE_"+e}deserialize(e){switch(e.type){case"number":return Number(e.value);case"boolean":return Boolean(e.value);case"object":return e.value;case"date":case"datetime":const t=new Date(e.value);return isNaN(t.getTime())?(console.error(`Invalid ${e.type} string:`,e.value),null):t;default:return String(e.value)}}}exports.CacheService=CacheService,__decorate([(0,logging_1.LogMethod)(),__metadata("design:type",Function),__metadata("design:paramtypes",[String,Object]),__metadata("design:returntype",Promise)],CacheService.prototype,"get",null),__decorate([(0,logging_1.LogMethod)(),__metadata("design:type",Function),__metadata("design:paramtypes",[String,Object,Object]),__metadata("design:returntype",Promise)],CacheService.prototype,"set",null);
1
+ "use strict";var __decorate=this&&this.__decorate||function(e,t,r,a){var i,n=arguments.length,o=n<3?t:null===a?a=Object.getOwnPropertyDescriptor(t,r):a;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,r,a);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(n<3?i(o):n>3?i(t,r,o):i(t,r))||o);return n>3&&o&&Object.defineProperty(t,r,o),o},__metadata=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},__awaiter=this&&this.__awaiter||function(e,t,r,a){return new(r||(r=Promise))((function(i,n){function o(e){try{c(a.next(e))}catch(e){n(e)}}function s(e){try{c(a.throw(e))}catch(e){n(e)}}function c(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(o,s)}c((a=a.apply(e,t||[])).next())}))},__importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.CacheService=void 0;const logging_1=require("../../logging"),logger_1=__importDefault(require("../../logging/logger")),KEY_PREFIX="Z_CACHE_",DEFAULT_TTL=36e5;class CacheService{constructor(e){this.storage=e}setSecondaryCache(e){this.secondaryCache=e}get(e,t){return __awaiter(this,void 0,void 0,(function*(){e=this.addPrefix(e);const r=yield this.storage.get(e);if(r)try{const t=JSON.parse(r);return t.expiresAt&&Date.now()>t.expiresAt?(yield this.delete(e),null):this.deserialize(t)}catch(e){return logger_1.default.error("Cache deserialization failed:",e),null}if((null==t?void 0:t.useSecondaryCache)&&this.secondaryCache){const r=yield this.secondaryCache.get(e,t);return null!==r&&(yield this.set(e,r,{ttl:null==t?void 0:t.ttl})),r}return null}))}set(e,t,r){return __awaiter(this,void 0,void 0,(function*(){var a;e=this.addPrefix(e);const i={type:t instanceof Date?"date":typeof t,value:t,expiresAt:Date.now()+(null!==(a=null==r?void 0:r.ttl)&&void 0!==a?a:36e5)},n=JSON.stringify(i);yield this.storage.set(e,n),(null==r?void 0:r.useSecondaryCache)&&this.secondaryCache&&(yield this.secondaryCache.set(e,t,r))}))}delete(e){return __awaiter(this,void 0,void 0,(function*(){e=this.addPrefix(e),yield this.storage.delete(e)}))}clear(){return __awaiter(this,void 0,void 0,(function*(){yield this.storage.clear()}))}addPrefix(e){return e.startsWith("Z_CACHE_")?e:"Z_CACHE_"+e}deserialize(e){switch(e.type){case"number":return Number(e.value);case"boolean":return Boolean(e.value);case"object":return e.value;case"date":case"datetime":const t=new Date(e.value);return isNaN(t.getTime())?(logger_1.default.error(`Invalid ${e.type} string:`,e.value),null):t;default:return String(e.value)}}}exports.CacheService=CacheService,__decorate([(0,logging_1.LogMethod)(),__metadata("design:type",Function),__metadata("design:paramtypes",[String,Object]),__metadata("design:returntype",Promise)],CacheService.prototype,"get",null),__decorate([(0,logging_1.LogMethod)(),__metadata("design:type",Function),__metadata("design:paramtypes",[String,Object,Object]),__metadata("design:returntype",Promise)],CacheService.prototype,"set",null);
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { PaginationStrategy } from "./pagination-strategy";
2
+ import { PaginationStrategy } from "../pagination-strategy";
3
3
  /**
4
4
  * Default configuration values for `GraphBatchConfig`.
5
5
  */
@@ -7,7 +7,7 @@ export declare const DEFAULT_GRAPH_BATCH_CONFIG: GraphBatchConfig;
7
7
  /**
8
8
  * Schema validation using `zod`
9
9
  */
10
- declare const GraphBatchConfigSchema: z.ZodObject<{
10
+ export declare const GraphBatchConfigSchema: z.ZodObject<{
11
11
  strategy: z.ZodNativeEnum<typeof PaginationStrategy>;
12
12
  batchSize: z.ZodDefault<z.ZodNumber>;
13
13
  maxBatches: z.ZodDefault<z.ZodNumber>;
@@ -31,4 +31,3 @@ export type GraphBatchConfig = z.infer<typeof GraphBatchConfigSchema>;
31
31
  * Merges user-provided config with default values.
32
32
  */
33
33
  export declare function initializeConfig(config: Partial<GraphBatchConfig> | undefined): GraphBatchConfig;
34
- export {};
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.GraphBatchConfigSchema=exports.DEFAULT_GRAPH_BATCH_CONFIG=void 0,exports.initializeConfig=initializeConfig;const zod_1=require("zod"),pagination_strategy_1=require("../pagination-strategy");function initializeConfig(e){return exports.GraphBatchConfigSchema.parse(Object.assign(Object.assign({},exports.DEFAULT_GRAPH_BATCH_CONFIG),e))}exports.DEFAULT_GRAPH_BATCH_CONFIG={strategy:pagination_strategy_1.PaginationStrategy.NONE,batchSize:200,maxBatches:100,delaySeconds:0},exports.GraphBatchConfigSchema=zod_1.z.object({strategy:zod_1.z.nativeEnum(pagination_strategy_1.PaginationStrategy),batchSize:zod_1.z.number().min(1).max(200).default(200),maxBatches:zod_1.z.number().min(1).max(500).default(100),delaySeconds:zod_1.z.number().min(0).max(15).default(0)});
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Default configuration values for `UniqueGraphBatchConfig`.
4
+ */
5
+ export declare const DEFAULT_UNIQUE_GRAPH_BATCH_CONFIG: UniqueGraphBatchConfig;
6
+ /**
7
+ * Schema validation for `UniqueGraphBatchConfig`
8
+ */
9
+ export declare const UniqueGraphBatchConfigSchema: z.ZodObject<z.objectUtil.extendShape<{
10
+ strategy: z.ZodNativeEnum<typeof import("..").PaginationStrategy>;
11
+ batchSize: z.ZodDefault<z.ZodNumber>;
12
+ maxBatches: z.ZodDefault<z.ZodNumber>;
13
+ delaySeconds: z.ZodDefault<z.ZodNumber>;
14
+ }, {
15
+ name: z.ZodOptional<z.ZodString>;
16
+ lockTtl: z.ZodOptional<z.ZodNumber>;
17
+ }>, "strip", z.ZodTypeAny, {
18
+ strategy: import("..").PaginationStrategy;
19
+ batchSize: number;
20
+ maxBatches: number;
21
+ delaySeconds: number;
22
+ name?: string | undefined;
23
+ lockTtl?: number | undefined;
24
+ }, {
25
+ strategy: import("..").PaginationStrategy;
26
+ name?: string | undefined;
27
+ batchSize?: number | undefined;
28
+ maxBatches?: number | undefined;
29
+ delaySeconds?: number | undefined;
30
+ lockTtl?: number | undefined;
31
+ }>;
32
+ /**
33
+ * Configuration options for `UniqueGraphBatch`.
34
+ */
35
+ export type UniqueGraphBatchConfig = z.infer<typeof UniqueGraphBatchConfigSchema>;
36
+ /**
37
+ * Merges user-provided config with default values for `UniqueGraphBatch`.
38
+ */
39
+ export declare function initializeUniqueConfig(config: Partial<UniqueGraphBatchConfig> | undefined): UniqueGraphBatchConfig;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.UniqueGraphBatchConfigSchema=exports.DEFAULT_UNIQUE_GRAPH_BATCH_CONFIG=void 0,exports.initializeUniqueConfig=initializeUniqueConfig;const zod_1=require("zod"),graph_batch_config_1=require("./graph-batch-config");function initializeUniqueConfig(e){return exports.UniqueGraphBatchConfigSchema.parse(Object.assign(Object.assign({},exports.DEFAULT_UNIQUE_GRAPH_BATCH_CONFIG),e))}exports.DEFAULT_UNIQUE_GRAPH_BATCH_CONFIG=Object.assign(Object.assign({},graph_batch_config_1.DEFAULT_GRAPH_BATCH_CONFIG),{lockTtl:96e4,name:"UNIQUE-BATCH"}),exports.UniqueGraphBatchConfigSchema=graph_batch_config_1.GraphBatchConfigSchema.extend({name:zod_1.z.string().optional(),lockTtl:zod_1.z.number().min(1e3).optional()});
@@ -1,7 +1,7 @@
1
1
  import { ExecutionContext } from "../../core";
2
2
  import { QueryResult } from "../../interfaces";
3
3
  import { GraphQLQueryBuilder } from "../graphql";
4
- import { GraphBatchConfig } from "./graph-batch-config";
4
+ import { GraphBatchConfig } from "./configs/graph-batch-config";
5
5
  /**
6
6
  * Base class for batch processing with pagination support.
7
7
  */
@@ -1 +1 @@
1
- "use strict";var __awaiter=this&&this.__awaiter||function(t,e,i,r){return new(i||(i=Promise))((function(a,s){function n(t){try{o(r.next(t))}catch(t){s(t)}}function h(t){try{o(r.throw(t))}catch(t){s(t)}}function o(t){var e;t.done?a(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(n,h)}o((r=r.apply(t,e||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.GraphBatch=void 0;const graph_batch_config_1=require("./graph-batch-config"),pagination_strategy_1=require("./pagination-strategy");class GraphBatch{constructor(t,e){this.startTime=new Date,this.context=t,this.config=(0,graph_batch_config_1.initializeConfig)(e),this.startTime=new Date}run(){return __awaiter(this,void 0,void 0,(function*(){var t,e;if(this.queryBuilder=yield this.start(),!this.queryBuilder)throw new Error("Query builder was not defined in start().");this.queryBuilder.withLimit(this.config.batchSize);let i=0,r=!0;for(;r&&!this.isMaxBatchesReached(i)&&(this.queryResult=yield this.fetchNextPage(),this.queryResult.records&&0!==this.queryResult.records.length);)yield this.execute(this.queryResult.records),i++,r=null!==(e=null===(t=this.queryResult.pageInfo)||void 0===t?void 0:t.hasNextPage)&&void 0!==e&&e;yield Promise.all([]),yield this.finish()}))}finish(){return __awaiter(this,void 0,void 0,(function*(){this.context.logger.info("Batch process completed.")}))}fetchNextPage(){return __awaiter(this,void 0,void 0,(function*(){var t,e,i;switch(this.config.strategy){case pagination_strategy_1.PaginationStrategy.OFFSET:this.queryResult&&(null===(t=this.queryBuilder)||void 0===t||t.withOffset(this.queryResult.endOffset+1));break;case pagination_strategy_1.PaginationStrategy.CURSOR:this.queryResult&&(null===(e=this.queryBuilder)||void 0===e||e.withCursor(this.queryResult.endCursor));break;case pagination_strategy_1.PaginationStrategy.NONE:default:null===(i=this.queryBuilder)||void 0===i||i.withFilter(`LastModifiedDate < ${this.startTime.toISOString()}`)}return this.queryBuilder.execute()}))}isMaxBatchesReached(t){return!!this.config.maxBatches&&t>=this.config.maxBatches}delay(t){return __awaiter(this,void 0,void 0,(function*(){return new Promise((e=>setTimeout(e,t)))}))}}exports.GraphBatch=GraphBatch;
1
+ "use strict";var __awaiter=this&&this.__awaiter||function(t,e,i,r){return new(i||(i=Promise))((function(a,s){function n(t){try{o(r.next(t))}catch(t){s(t)}}function h(t){try{o(r.throw(t))}catch(t){s(t)}}function o(t){var e;t.done?a(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(n,h)}o((r=r.apply(t,e||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.GraphBatch=void 0;const graph_batch_config_1=require("./configs/graph-batch-config"),pagination_strategy_1=require("./pagination-strategy");class GraphBatch{constructor(t,e){this.startTime=new Date,this.context=t,this.config=(0,graph_batch_config_1.initializeConfig)(e),this.startTime=new Date}run(){return __awaiter(this,void 0,void 0,(function*(){var t,e;if(this.queryBuilder=yield this.start(),!this.queryBuilder)throw new Error("Query builder was not defined in start().");this.queryBuilder.withLimit(this.config.batchSize);let i=0,r=!0;for(;r&&!this.isMaxBatchesReached(i)&&(this.queryResult=yield this.fetchNextPage(),this.queryResult.records&&0!==this.queryResult.records.length);)yield this.execute(this.queryResult.records),i++,r=null!==(e=null===(t=this.queryResult.pageInfo)||void 0===t?void 0:t.hasNextPage)&&void 0!==e&&e;yield this.finish()}))}finish(){return __awaiter(this,void 0,void 0,(function*(){this.context.logger.info("Batch process completed.")}))}fetchNextPage(){return __awaiter(this,void 0,void 0,(function*(){var t,e,i;switch(this.config.strategy){case pagination_strategy_1.PaginationStrategy.OFFSET:this.queryResult&&(null===(t=this.queryBuilder)||void 0===t||t.withOffset(this.queryResult.endOffset+1));break;case pagination_strategy_1.PaginationStrategy.CURSOR:this.queryResult&&(null===(e=this.queryBuilder)||void 0===e||e.withCursor(this.queryResult.endCursor));break;case pagination_strategy_1.PaginationStrategy.NONE:default:null===(i=this.queryBuilder)||void 0===i||i.withFilter(`LastModifiedDate < ${this.startTime.toISOString()}`)}return this.queryBuilder.execute()}))}isMaxBatchesReached(t){return!!this.config.maxBatches&&t>=this.config.maxBatches}delay(t){return __awaiter(this,void 0,void 0,(function*(){return new Promise((e=>setTimeout(e,t)))}))}}exports.GraphBatch=GraphBatch;
@@ -1,3 +1,5 @@
1
+ export * from "./configs/graph-batch-config";
2
+ export * from "./configs/unique-graph-batch-config";
1
3
  export * from "./graph-batch";
2
- export * from "./graph-batch-config";
3
4
  export * from "./pagination-strategy";
5
+ export * from "./unique-graph-batch";
@@ -1 +1 @@
1
- "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,r,i){void 0===i&&(i=r);var o=Object.getOwnPropertyDescriptor(t,r);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,i,o)}:function(e,t,r,i){void 0===i&&(i=r),e[i]=t[r]}),__exportStar=this&&this.__exportStar||function(e,t){for(var r in e)"default"===r||Object.prototype.hasOwnProperty.call(t,r)||__createBinding(t,e,r)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("./graph-batch"),exports),__exportStar(require("./graph-batch-config"),exports),__exportStar(require("./pagination-strategy"),exports);
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,r,t,i){void 0===i&&(i=t);var o=Object.getOwnPropertyDescriptor(r,t);o&&!("get"in o?!r.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return r[t]}}),Object.defineProperty(e,i,o)}:function(e,r,t,i){void 0===i&&(i=t),e[i]=r[t]}),__exportStar=this&&this.__exportStar||function(e,r){for(var t in e)"default"===t||Object.prototype.hasOwnProperty.call(r,t)||__createBinding(r,e,t)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("./configs/graph-batch-config"),exports),__exportStar(require("./configs/unique-graph-batch-config"),exports),__exportStar(require("./graph-batch"),exports),__exportStar(require("./pagination-strategy"),exports),__exportStar(require("./unique-graph-batch"),exports);
@@ -0,0 +1,28 @@
1
+ import { ExecutionContext } from "../../core/execution-context";
2
+ import { GraphQLQueryBuilder } from "../graphql";
3
+ import { UniqueGraphBatchConfig } from "./configs/unique-graph-batch-config";
4
+ import { GraphBatch } from "./graph-batch";
5
+ /**
6
+ * UniqueGraphBatch ensures that only one instance of a batch with the same name can run at a time.
7
+ */
8
+ export declare class UniqueGraphBatch extends GraphBatch {
9
+ private name;
10
+ private lockTtl;
11
+ constructor(context: ExecutionContext, config?: Partial<UniqueGraphBatchConfig>);
12
+ /**
13
+ * Runs the batch process with lock enforcement.
14
+ */
15
+ run(): Promise<void>;
16
+ /**
17
+ * Abstract method implementation - Initialize query builder.
18
+ */
19
+ protected start(): Promise<GraphQLQueryBuilder>;
20
+ /**
21
+ * Abstract method implementation - Process batch records.
22
+ */
23
+ protected execute(records: any[]): Promise<void>;
24
+ /**
25
+ * Overrides the finish method to ensure lock cleanup.
26
+ */
27
+ protected finish(): Promise<void>;
28
+ }
@@ -0,0 +1 @@
1
+ "use strict";var __awaiter=this&&this.__awaiter||function(t,e,r,i){return new(r||(r=Promise))((function(n,a){function o(t){try{s(i.next(t))}catch(t){a(t)}}function c(t){try{s(i.throw(t))}catch(t){a(t)}}function s(t){var e;t.done?n(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(o,c)}s((i=i.apply(t,e||[])).next())}))},__importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.UniqueGraphBatch=void 0;const logger_1=__importDefault(require("../../logging/logger")),graph_batch_1=require("./graph-batch");class UniqueGraphBatch extends graph_batch_1.GraphBatch{constructor(t,e){super(t,e),this.name=(null==e?void 0:e.name)||this.constructor.name,this.name=this.name.toUpperCase().replace(/[^A-Z0-9]/g,"_"),this.lockTtl=(null==e?void 0:e.lockTtl)||96e4}run(){const t=Object.create(null,{run:{get:()=>super.run}});return __awaiter(this,void 0,void 0,(function*(){const e={name:this.name,ttl:this.lockTtl,description:`Lock for batch process: ${this.name}`};try{if(!(yield this.context.lockService.acquireLock(e)))return void logger_1.default.error(`A batch with name '${this.name}' is already running.`);yield t.run.call(this)}catch(t){logger_1.default.error(`Error running batch with name '${this.name}': ${t.message}`)}finally{yield this.context.lockService.releaseLock(this.name)}}))}start(){return __awaiter(this,void 0,void 0,(function*(){throw new Error("Subclasses must implement the 'start' method.")}))}execute(t){return __awaiter(this,void 0,void 0,(function*(){throw new Error("Subclasses must implement the 'execute' method.")}))}finish(){const t=Object.create(null,{finish:{get:()=>super.finish}});return __awaiter(this,void 0,void 0,(function*(){yield t.finish.call(this)}))}}exports.UniqueGraphBatch=UniqueGraphBatch;
@@ -0,0 +1 @@
1
+ "use strict";var __decorate=this&&this.__decorate||function(e,t,r,i){var o,n=arguments.length,a=n<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,r,i);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(a=(n<3?o(a):n>3?o(t,r,a):o(t,r))||a);return n>3&&a&&Object.defineProperty(t,r,a),a},__metadata=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},__awaiter=this&&this.__awaiter||function(e,t,r,i){return new(r||(r=Promise))((function(o,n){function a(e){try{l(i.next(e))}catch(e){n(e)}}function c(e){try{l(i.throw(e))}catch(e){n(e)}}function l(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,c)}l((i=i.apply(e,t||[])).next())}))},__importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.LockService=void 0;const logging_1=require("../logging"),logger_1=__importDefault(require("../logging/logger")),KEY_PREFIX="Z_LOCK_";class LockService{constructor(e){this.configVarClient=e}acquireLock(e){return __awaiter(this,void 0,void 0,(function*(){const t="Z_LOCK_"+e.name,r=new Date(Date.now()+e.ttl).toISOString();try{let i=null;try{i=yield this.configVarClient.get(t)}catch(e){}if(i){if(i.expiryDate&&new Date<new Date(i.expiryDate))return!1;yield this.configVarClient.delete(t)}return yield this.configVarClient.create({key:t,value:e.name,configType:"plain-text",description:e.description,expiryDate:r}),!0}catch(t){return logger_1.default.error(`Failed to acquire lock: ${e.name}`),!1}}))}releaseLock(e){return __awaiter(this,void 0,void 0,(function*(){const t="Z_LOCK_"+e;try{let e=null;try{e=yield this.configVarClient.get(t)}catch(e){}e&&(yield this.configVarClient.delete(t))}catch(t){logger_1.default.error(`Failed to release lock: ${e}`)}}))}}exports.LockService=LockService,__decorate([(0,logging_1.LogMethod)(),__metadata("design:type",Function),__metadata("design:paramtypes",[Object]),__metadata("design:returntype",Promise)],LockService.prototype,"acquireLock",null),__decorate([(0,logging_1.LogMethod)(),__metadata("design:type",Function),__metadata("design:paramtypes",[String]),__metadata("design:returntype",Promise)],LockService.prototype,"releaseLock",null);
@@ -0,0 +1 @@
1
+ "use strict";var __awaiter=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))((function(r,c){function o(e){try{l(n.next(e))}catch(e){c(e)}}function a(e){try{l(n.throw(e))}catch(e){c(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(o,a)}l((n=n.apply(e,t||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.LockingService=void 0;const KEY_PREFIX="Z_LOCK_";class LockingService{constructor(e){this.configVarClient=e}acquireLock(e){return __awaiter(this,void 0,void 0,(function*(){const t="Z_LOCK_"+e.name,i=new Date(Date.now()+e.ttl).toISOString();try{let n=null;try{n=yield this.configVarClient.get(t)}catch(e){}if(n){if(n.expiryDate&&new Date<new Date(n.expiryDate))return!1;yield this.configVarClient.delete(t)}return yield this.configVarClient.create({key:t,value:e.name,configType:"plain-text",description:e.description,expiryDate:i}),!0}catch(t){return console.error(`Failed to acquire lock: ${e.name}`),!1}}))}releaseLock(e){return __awaiter(this,void 0,void 0,(function*(){const t="Z_LOCK_"+e;try{let e=null;try{e=yield this.configVarClient.get(t)}catch(e){}e&&(yield this.configVarClient.delete(t))}catch(t){console.error(`Failed to release lock: ${e}`)}}))}}exports.LockingService=LockingService;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.DateTimeUtils=void 0;const luxon_1=require("luxon");class DateTimeUtils{static toTimezone(t,e){return this.switchTimezone(t,"UTC",e)}static switchTimezone(t,e,a){if(e===a)return t;return luxon_1.DateTime.fromJSDate(t,{zone:e}).setZone(a).toJSDate()}static addMinutes(t,e,a){return luxon_1.DateTime.fromJSDate(t,{zone:a}).plus({minutes:e}).toJSDate()}static addDays(t,e,a){return luxon_1.DateTime.fromJSDate(t,{zone:a}).plus({days:e}).toJSDate()}static addMonths(t,e,a){return luxon_1.DateTime.fromJSDate(t,{zone:a}).plus({months:e}).toJSDate()}static addYears(t,e,a){return luxon_1.DateTime.fromJSDate(t,{zone:a}).plus({years:e}).toJSDate()}static getDate(t,e){return luxon_1.DateTime.fromJSDate(t,{zone:e}).startOf("day").toJSDate()}static getDateFromIsoString(t){return luxon_1.DateTime.fromISO(t,{zone:"UTC"}).toJSDate()}static getDateTimeFromIsoString(t){return luxon_1.DateTime.fromISO(t,{zone:"UTC"}).toJSDate()}static getStartOfDate(t,e){const a="string"==typeof t?this.getDateFromIsoString(t):t;return luxon_1.DateTime.fromJSDate(a,{zone:e}).startOf("day").toJSDate()}static getEndOfDate(t,e){const a=this.getStartOfDate(t,e);return this.addDays(a,1,e)}static isIncluding(t,e){return t.start<=e.start&&t.finish>=e.finish}static isOverlapping(t,e){return t.start<e.finish&&t.finish>e.start}static mergeEvents(t){t.sort(((t,e)=>t.start.getTime()-e.start.getTime()));const e=[];let a=null;for(const i of t)a?new Date(a.finish)>=i.start?(a.finish=i.finish,a.eventType="merged",a.description=a.description?`${a.description}, ${a.name} merged with ${i.name}`:`${a.name} merged with ${i.name}`):(e.push(a),a=i):a=i;return a&&e.push(a),e}}exports.DateTimeUtils=DateTimeUtils;
1
+ "use strict";var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.DateTimeUtils=void 0;const dayjs_1=__importDefault(require("dayjs")),timezone_1=__importDefault(require("dayjs/plugin/timezone")),utc_1=__importDefault(require("dayjs/plugin/utc"));dayjs_1.default.extend(utc_1.default),dayjs_1.default.extend(timezone_1.default);class DateTimeUtils{static toTimezone(t,e){return(0,dayjs_1.default)(t).tz(e).toDate()}static switchTimezone(t,e,a){return e===a?t:(0,dayjs_1.default)(t).tz(e).tz(a).toDate()}static addMinutes(t,e,a){return(0,dayjs_1.default)(t).tz(a).add(e,"minute").toDate()}static addDays(t,e,a){return(0,dayjs_1.default)(t).tz(a).add(e,"day").toDate()}static addMonths(t,e,a){return(0,dayjs_1.default)(t).tz(a).add(e,"month").toDate()}static addYears(t,e,a){return(0,dayjs_1.default)(t).tz(a).add(e,"year").toDate()}static getDate(t,e){return(0,dayjs_1.default)(t).tz(e).startOf("day").toDate()}static getDateFromIsoString(t){return(0,dayjs_1.default)(t).utc().toDate()}static getDateTimeFromIsoString(t){return(0,dayjs_1.default)(t).utc().toDate()}static getStartOfDate(t,e){const a="string"==typeof t?this.getDateFromIsoString(t):t;return(0,dayjs_1.default)(a).tz(e).startOf("day").toDate()}static getEndOfDate(t,e){return this.addDays(this.getStartOfDate(t,e),1,e)}static isIncluding(t,e){return t.start<=e.start&&t.finish>=e.finish}static isOverlapping(t,e){return t.start<e.finish&&t.finish>e.start}static mergeEvents(t){t.sort(((t,e)=>t.start.getTime()-e.start.getTime()));const e=[];let a=null;for(const s of t)a?a.finish>=s.start?(a.finish=s.finish,a.eventType="merged",a.description=a.description?`${a.description}, ${a.name} merged with ${s.name}`:`${a.name} merged with ${s.name}`):(e.push(a),a=s):a=s;return a&&e.push(a),e}}exports.DateTimeUtils=DateTimeUtils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skedulo/pulse-solution-services",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "A collection of services and utilities to support solution development on the Pulse platform.",
5
5
  "author": "Skedulo",
6
6
  "license": "MIT",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "devDependencies": {
25
25
  "@tsconfig/node18": "^18.2.2",
26
+ "@types/uuid": "^10.0.0",
26
27
  "@typescript-eslint/eslint-plugin": "^8.11.0",
27
28
  "@typescript-eslint/parser": "^8.11.0",
28
29
  "dts-bundle-generator": "^9.5.1",
@@ -37,11 +38,12 @@
37
38
  },
38
39
  "dependencies": {
39
40
  "@skedulo/function-utilities": "^0.0.6",
40
- "@types/luxon": "^3.4.2",
41
- "luxon": "^3.5.0",
41
+ "dayjs": "^1.11.13",
42
42
  "p-queue": "^8.1.0",
43
+ "timezone": "^1.0.23",
43
44
  "typescript": "~5.6.3",
44
- "uuid": "^11.0.5",
45
+ "utc": "^0.1.0",
46
+ "uuid": "8",
45
47
  "winston": "^3.17.0",
46
48
  "zod": "^3.24.2"
47
49
  }