@machinemetrics/mm-erp-sdk 0.1.1-beta.1
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/LICENSE +21 -0
- package/README.md +147 -0
- package/dist/config-2l5vnNkA.js +418 -0
- package/dist/config-2l5vnNkA.js.map +1 -0
- package/dist/connector-factory-CQ8e7Tae.js +21 -0
- package/dist/connector-factory-CQ8e7Tae.js.map +1 -0
- package/dist/hashed-cache-manager-Ci9X3GAB.js +292 -0
- package/dist/hashed-cache-manager-Ci9X3GAB.js.map +1 -0
- package/dist/index-Cn9ccxOO.js +179 -0
- package/dist/index-Cn9ccxOO.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/knexfile-1qKKIORB.js +20 -0
- package/dist/knexfile-1qKKIORB.js.map +1 -0
- package/dist/knexfile.d.ts +6 -0
- package/dist/knexfile.d.ts.map +1 -0
- package/dist/logger-QG73MndU.js +17523 -0
- package/dist/logger-QG73MndU.js.map +1 -0
- package/dist/migrations/20241015162631_create_cache_table.js +17 -0
- package/dist/migrations/20241015162631_create_cache_table.js.map +1 -0
- package/dist/migrations/20241015162632_create_sdk_cache_table.js +17 -0
- package/dist/migrations/20241015162632_create_sdk_cache_table.js.map +1 -0
- package/dist/migrations/20250103162631_create_record_tracking_table.js +17 -0
- package/dist/migrations/20250103162631_create_record_tracking_table.js.map +1 -0
- package/dist/mm-erp-sdk.js +3503 -0
- package/dist/mm-erp-sdk.js.map +1 -0
- package/dist/services/caching-service/batch-cache-manager.d.ts +52 -0
- package/dist/services/caching-service/batch-cache-manager.d.ts.map +1 -0
- package/dist/services/caching-service/hashed-cache-manager.d.ts +83 -0
- package/dist/services/caching-service/hashed-cache-manager.d.ts.map +1 -0
- package/dist/services/caching-service/index.d.ts +92 -0
- package/dist/services/caching-service/index.d.ts.map +1 -0
- package/dist/services/caching-service/record-tracking-manager.d.ts +15 -0
- package/dist/services/caching-service/record-tracking-manager.d.ts.map +1 -0
- package/dist/services/data-sync-service/configuration-manager.d.ts +50 -0
- package/dist/services/data-sync-service/configuration-manager.d.ts.map +1 -0
- package/dist/services/data-sync-service/data-sync-service.d.ts +2 -0
- package/dist/services/data-sync-service/data-sync-service.d.ts.map +1 -0
- package/dist/services/data-sync-service/index.d.ts +10 -0
- package/dist/services/data-sync-service/index.d.ts.map +1 -0
- package/dist/services/data-sync-service/jobs/clean-up-expired-cache.d.ts +2 -0
- package/dist/services/data-sync-service/jobs/clean-up-expired-cache.d.ts.map +1 -0
- package/dist/services/data-sync-service/jobs/clean-up-expired-cache.js +41 -0
- package/dist/services/data-sync-service/jobs/clean-up-expired-cache.js.map +1 -0
- package/dist/services/data-sync-service/jobs/from-erp.d.ts +4 -0
- package/dist/services/data-sync-service/jobs/from-erp.d.ts.map +1 -0
- package/dist/services/data-sync-service/jobs/from-erp.js +42 -0
- package/dist/services/data-sync-service/jobs/from-erp.js.map +1 -0
- package/dist/services/data-sync-service/jobs/retry-failed-labor-tickets.d.ts +2 -0
- package/dist/services/data-sync-service/jobs/retry-failed-labor-tickets.d.ts.map +1 -0
- package/dist/services/data-sync-service/jobs/retry-failed-labor-tickets.js +41 -0
- package/dist/services/data-sync-service/jobs/retry-failed-labor-tickets.js.map +1 -0
- package/dist/services/data-sync-service/jobs/run-migrations.d.ts +2 -0
- package/dist/services/data-sync-service/jobs/run-migrations.d.ts.map +1 -0
- package/dist/services/data-sync-service/jobs/run-migrations.js +21 -0
- package/dist/services/data-sync-service/jobs/run-migrations.js.map +1 -0
- package/dist/services/data-sync-service/jobs/to-erp.d.ts +4 -0
- package/dist/services/data-sync-service/jobs/to-erp.d.ts.map +1 -0
- package/dist/services/data-sync-service/jobs/to-erp.js +39 -0
- package/dist/services/data-sync-service/jobs/to-erp.js.map +1 -0
- package/dist/services/erp-api-services/errors.d.ts +22 -0
- package/dist/services/erp-api-services/errors.d.ts.map +1 -0
- package/dist/services/erp-api-services/graphql/graphql-service.d.ts +40 -0
- package/dist/services/erp-api-services/graphql/graphql-service.d.ts.map +1 -0
- package/dist/services/erp-api-services/graphql/types.d.ts +32 -0
- package/dist/services/erp-api-services/graphql/types.d.ts.map +1 -0
- package/dist/services/erp-api-services/index.d.ts +9 -0
- package/dist/services/erp-api-services/index.d.ts.map +1 -0
- package/dist/services/erp-api-services/oauth-client.d.ts +45 -0
- package/dist/services/erp-api-services/oauth-client.d.ts.map +1 -0
- package/dist/services/erp-api-services/rest/get-query-params.d.ts +50 -0
- package/dist/services/erp-api-services/rest/get-query-params.d.ts.map +1 -0
- package/dist/services/erp-api-services/rest/rest-api-service.d.ts +35 -0
- package/dist/services/erp-api-services/rest/rest-api-service.d.ts.map +1 -0
- package/dist/services/erp-api-services/types.d.ts +27 -0
- package/dist/services/erp-api-services/types.d.ts.map +1 -0
- package/dist/services/mm-api-service/index.d.ts +31 -0
- package/dist/services/mm-api-service/index.d.ts.map +1 -0
- package/dist/services/mm-api-service/mm-api-service.d.ts +214 -0
- package/dist/services/mm-api-service/mm-api-service.d.ts.map +1 -0
- package/dist/services/mm-api-service/token-mgr.d.ts +33 -0
- package/dist/services/mm-api-service/token-mgr.d.ts.map +1 -0
- package/dist/services/mm-api-service/types/checkpoint.d.ts +13 -0
- package/dist/services/mm-api-service/types/checkpoint.d.ts.map +1 -0
- package/dist/services/mm-api-service/types/entity-transformer.d.ts +58 -0
- package/dist/services/mm-api-service/types/entity-transformer.d.ts.map +1 -0
- package/dist/services/mm-api-service/types/mm-response-interfaces.d.ts +263 -0
- package/dist/services/mm-api-service/types/mm-response-interfaces.d.ts.map +1 -0
- package/dist/services/mm-api-service/types/receive-types.d.ts +57 -0
- package/dist/services/mm-api-service/types/receive-types.d.ts.map +1 -0
- package/dist/services/mm-api-service/types/send-types.d.ts +147 -0
- package/dist/services/mm-api-service/types/send-types.d.ts.map +1 -0
- package/dist/services/reporting-service/index.d.ts +5 -0
- package/dist/services/reporting-service/index.d.ts.map +1 -0
- package/dist/services/reporting-service/logger.d.ts +4 -0
- package/dist/services/reporting-service/logger.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/configuration.d.ts +15 -0
- package/dist/services/sql-server-erp-service/configuration.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/index.d.ts +16 -0
- package/dist/services/sql-server-erp-service/index.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/internal/sql-labor-ticket-operations.d.ts +31 -0
- package/dist/services/sql-server-erp-service/internal/sql-labor-ticket-operations.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/internal/sql-server-config.d.ts +65 -0
- package/dist/services/sql-server-erp-service/internal/sql-server-config.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/internal/sql-transaction-manager.d.ts +20 -0
- package/dist/services/sql-server-erp-service/internal/sql-transaction-manager.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/internal/types/sql-server-types.d.ts +3 -0
- package/dist/services/sql-server-erp-service/internal/types/sql-server-types.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/sql-server-helpers.d.ts +35 -0
- package/dist/services/sql-server-erp-service/sql-server-helpers.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/sql-server-service.d.ts +37 -0
- package/dist/services/sql-server-erp-service/sql-server-service.d.ts.map +1 -0
- package/dist/services/sql-server-erp-service/types/sql-input-param.d.ts +10 -0
- package/dist/services/sql-server-erp-service/types/sql-input-param.d.ts.map +1 -0
- package/dist/services/sqlite-service/index.d.ts +2 -0
- package/dist/services/sqlite-service/index.d.ts.map +1 -0
- package/dist/services/sqlite-service/sqlite-coordinator.d.ts +28 -0
- package/dist/services/sqlite-service/sqlite-coordinator.d.ts.map +1 -0
- package/dist/types/erp-connector.d.ts +40 -0
- package/dist/types/erp-connector.d.ts.map +1 -0
- package/dist/types/erp-types.d.ts +32 -0
- package/dist/types/erp-types.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/application-initializer.d.ts +15 -0
- package/dist/utils/application-initializer.d.ts.map +1 -0
- package/dist/utils/cleanup-numbers.d.ts +2 -0
- package/dist/utils/cleanup-numbers.d.ts.map +1 -0
- package/dist/utils/connector-factory.d.ts +8 -0
- package/dist/utils/connector-factory.d.ts.map +1 -0
- package/dist/utils/data-transformation.d.ts +20 -0
- package/dist/utils/data-transformation.d.ts.map +1 -0
- package/dist/utils/erp-type-from-entity.d.ts +5 -0
- package/dist/utils/erp-type-from-entity.d.ts.map +1 -0
- package/dist/utils/http-client.d.ts +35 -0
- package/dist/utils/http-client.d.ts.map +1 -0
- package/dist/utils/index.d.ts +57 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/local-data-store/database-lock.d.ts +29 -0
- package/dist/utils/local-data-store/database-lock.d.ts.map +1 -0
- package/dist/utils/local-data-store/jobs-shared-data.d.ts +34 -0
- package/dist/utils/local-data-store/jobs-shared-data.d.ts.map +1 -0
- package/dist/utils/mm-labor-ticket-helpers.d.ts +9 -0
- package/dist/utils/mm-labor-ticket-helpers.d.ts.map +1 -0
- package/dist/utils/removeExtraneousFields.d.ts +6 -0
- package/dist/utils/removeExtraneousFields.d.ts.map +1 -0
- package/dist/utils/removeIdFieldFromPayload.d.ts +6 -0
- package/dist/utils/removeIdFieldFromPayload.d.ts.map +1 -0
- package/dist/utils/resource-group.d.ts +11 -0
- package/dist/utils/resource-group.d.ts.map +1 -0
- package/dist/utils/standard-process-drivers/error-processor.d.ts +68 -0
- package/dist/utils/standard-process-drivers/error-processor.d.ts.map +1 -0
- package/dist/utils/standard-process-drivers/index.d.ts +3 -0
- package/dist/utils/standard-process-drivers/index.d.ts.map +1 -0
- package/dist/utils/standard-process-drivers/labor-ticket-erp-synchronizer.d.ts +18 -0
- package/dist/utils/standard-process-drivers/labor-ticket-erp-synchronizer.d.ts.map +1 -0
- package/dist/utils/standard-process-drivers/mm-entity-processor.d.ts +40 -0
- package/dist/utils/standard-process-drivers/mm-entity-processor.d.ts.map +1 -0
- package/dist/utils/standard-process-drivers/standard-process-drivers.d.ts +178 -0
- package/dist/utils/standard-process-drivers/standard-process-drivers.d.ts.map +1 -0
- package/dist/utils/time-utils.d.ts +31 -0
- package/dist/utils/time-utils.d.ts.map +1 -0
- package/dist/utils/timezone.d.ts +21 -0
- package/dist/utils/timezone.d.ts.map +1 -0
- package/dist/utils/trimObjectValues.d.ts +5 -0
- package/dist/utils/trimObjectValues.d.ts.map +1 -0
- package/dist/utils/uniqueRows.d.ts +9 -0
- package/dist/utils/uniqueRows.d.ts.map +1 -0
- package/package.json +50 -0
- package/src/index.ts +98 -0
- package/src/knexfile.ts +21 -0
- package/src/migrations/20241015162631_create_cache_table.ts +15 -0
- package/src/migrations/20241015162632_create_sdk_cache_table.ts +15 -0
- package/src/migrations/20250103162631_create_record_tracking_table.ts +18 -0
- package/src/services/caching-service/batch-cache-manager.ts +111 -0
- package/src/services/caching-service/hashed-cache-manager.ts +253 -0
- package/src/services/caching-service/index.ts +114 -0
- package/src/services/caching-service/record-tracking-manager.ts +41 -0
- package/src/services/data-sync-service/configuration-manager.ts +153 -0
- package/src/services/data-sync-service/data-sync-service.ts +100 -0
- package/src/services/data-sync-service/index.ts +14 -0
- package/src/services/data-sync-service/jobs/clean-up-expired-cache.ts +38 -0
- package/src/services/data-sync-service/jobs/from-erp.ts +55 -0
- package/src/services/data-sync-service/jobs/retry-failed-labor-tickets.ts +44 -0
- package/src/services/data-sync-service/jobs/run-migrations.ts +21 -0
- package/src/services/data-sync-service/jobs/to-erp.ts +53 -0
- package/src/services/erp-api-services/errors.ts +115 -0
- package/src/services/erp-api-services/graphql/graphql-service.ts +116 -0
- package/src/services/erp-api-services/graphql/types.ts +30 -0
- package/src/services/erp-api-services/index.ts +14 -0
- package/src/services/erp-api-services/oauth-client.ts +72 -0
- package/src/services/erp-api-services/rest/get-query-params.ts +63 -0
- package/src/services/erp-api-services/rest/rest-api-service.ts +212 -0
- package/src/services/erp-api-services/types.ts +28 -0
- package/src/services/mm-api-service/index.ts +83 -0
- package/src/services/mm-api-service/mm-api-service.ts +685 -0
- package/src/services/mm-api-service/token-mgr.ts +123 -0
- package/src/services/mm-api-service/types/checkpoint.ts +13 -0
- package/src/services/mm-api-service/types/entity-transformer.ts +298 -0
- package/src/services/mm-api-service/types/mm-response-interfaces.ts +293 -0
- package/src/services/mm-api-service/types/receive-types.ts +89 -0
- package/src/services/mm-api-service/types/send-types.ts +383 -0
- package/src/services/reporting-service/index.ts +4 -0
- package/src/services/reporting-service/logger.ts +117 -0
- package/src/services/sql-server-erp-service/configuration.ts +14 -0
- package/src/services/sql-server-erp-service/index.ts +18 -0
- package/src/services/sql-server-erp-service/internal/sql-labor-ticket-operations.ts +66 -0
- package/src/services/sql-server-erp-service/internal/sql-server-config.ts +38 -0
- package/src/services/sql-server-erp-service/internal/sql-transaction-manager.ts +45 -0
- package/src/services/sql-server-erp-service/internal/types/sql-server-types.ts +23 -0
- package/src/services/sql-server-erp-service/sql-server-helpers.ts +99 -0
- package/src/services/sql-server-erp-service/sql-server-service.ts +191 -0
- package/src/services/sql-server-erp-service/types/sql-input-param.ts +14 -0
- package/src/services/sqlite-service/index.ts +1 -0
- package/src/services/sqlite-service/sqlite-coordinator.ts +80 -0
- package/src/types/erp-connector.ts +46 -0
- package/src/types/erp-types.ts +37 -0
- package/src/types/index.ts +13 -0
- package/src/utils/application-initializer.ts +62 -0
- package/src/utils/cleanup-numbers.ts +5 -0
- package/src/utils/connector-factory.ts +34 -0
- package/src/utils/data-transformation.ts +58 -0
- package/src/utils/erp-type-from-entity.ts +12 -0
- package/src/utils/http-client.ts +137 -0
- package/src/utils/index.ts +71 -0
- package/src/utils/local-data-store/database-lock.ts +86 -0
- package/src/utils/local-data-store/jobs-shared-data.ts +111 -0
- package/src/utils/mm-labor-ticket-helpers.ts +28 -0
- package/src/utils/removeExtraneousFields.ts +22 -0
- package/src/utils/removeIdFieldFromPayload.ts +22 -0
- package/src/utils/resource-group.ts +92 -0
- package/src/utils/standard-process-drivers/error-processor.ts +417 -0
- package/src/utils/standard-process-drivers/index.ts +6 -0
- package/src/utils/standard-process-drivers/labor-ticket-erp-synchronizer.ts +261 -0
- package/src/utils/standard-process-drivers/mm-entity-processor.ts +265 -0
- package/src/utils/standard-process-drivers/standard-process-drivers.ts +459 -0
- package/src/utils/time-utils.ts +131 -0
- package/src/utils/timezone.ts +96 -0
- package/src/utils/trimObjectValues.ts +12 -0
- package/src/utils/uniqueRows.ts +40 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import Bree, { Job } from "bree";
|
|
2
|
+
import Graceful from "@ladjs/graceful";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { CoreConfiguration } from "./configuration-manager";
|
|
6
|
+
import logger from "../reporting-service/logger";
|
|
7
|
+
|
|
8
|
+
export const runDataSyncService = async (connectorPath: string) => {
|
|
9
|
+
const config = CoreConfiguration.inst();
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
// Find the SDK's node_modules directory and jobs path using ES module import
|
|
13
|
+
const currentFileUrl = import.meta.url;
|
|
14
|
+
const currentFilePath = fileURLToPath(currentFileUrl);
|
|
15
|
+
|
|
16
|
+
// Navigate from current file to the SDK root and then to jobs
|
|
17
|
+
// Current: /path/to/sdk/dist/mm-erp-sdk.js.js
|
|
18
|
+
// Target: /path/to/sdk/dist/services/data-sync-service/jobs
|
|
19
|
+
const sdkDistPath = path.dirname(currentFilePath);
|
|
20
|
+
const jobsPath = path.join(
|
|
21
|
+
sdkDistPath,
|
|
22
|
+
"services",
|
|
23
|
+
"data-sync-service",
|
|
24
|
+
"jobs"
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const bree = new Bree({
|
|
28
|
+
root: jobsPath,
|
|
29
|
+
logger,
|
|
30
|
+
worker: {
|
|
31
|
+
env: {
|
|
32
|
+
CONNECTOR_PATH: connectorPath,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
jobs: [
|
|
36
|
+
// {
|
|
37
|
+
// name: 'run-migrations', // Running this once on startup will create the tables in the sqlite database
|
|
38
|
+
// },
|
|
39
|
+
{
|
|
40
|
+
name: "from-erp",
|
|
41
|
+
timeout: "10s",
|
|
42
|
+
interval: config.fromErpInterval,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "to-erp",
|
|
46
|
+
//timeout: '3s', // Use timeout during development to see the job in action quickly
|
|
47
|
+
interval: config.toErpInterval,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "retry-failed-labor-tickets",
|
|
51
|
+
interval: config.retryLaborTicketsInterval,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "clean-up-expired-cache",
|
|
55
|
+
interval: config.cacheExpirationCheckInterval,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
logger.info(
|
|
61
|
+
"\n================================INITIATING DATA SYNC CYCLES (Bree)================================\n"
|
|
62
|
+
);
|
|
63
|
+
const jobsConfig = bree.config.jobs.map((job: Job) => ({
|
|
64
|
+
name: job.name,
|
|
65
|
+
interval: job.interval,
|
|
66
|
+
timeout: job.timeout,
|
|
67
|
+
}));
|
|
68
|
+
logger.info("JOBS CONFIGURATION:", { jobs: jobsConfig });
|
|
69
|
+
|
|
70
|
+
const graceful = new Graceful({ brees: [bree] });
|
|
71
|
+
graceful.listen();
|
|
72
|
+
|
|
73
|
+
(async () => {
|
|
74
|
+
await bree.start();
|
|
75
|
+
})();
|
|
76
|
+
|
|
77
|
+
bree.on("jobStarted", (job) => {
|
|
78
|
+
console.log("Job " + job.name + " started");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
bree.on("jobCompleted", (job) => {
|
|
82
|
+
if (job.error) {
|
|
83
|
+
console.error("Job " + job.name + " failed:", job.error);
|
|
84
|
+
} else {
|
|
85
|
+
console.log("Job " + job.name + " completed successfully!");
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
bree.on("error", (error) => {
|
|
90
|
+
console.error("Bree error:", error);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Exit and let the jobs take over
|
|
94
|
+
logger.info(
|
|
95
|
+
"\n================================DATA SYNC CYCLES INITIATION COMPLETED================================\n"
|
|
96
|
+
);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
logger.error("startUp: Error initiating data sync cycles:", error);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core data sync service functionality
|
|
3
|
+
*/
|
|
4
|
+
export { runDataSyncService } from "./data-sync-service";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configuration management for data sync
|
|
8
|
+
*/
|
|
9
|
+
export { getSQLServerConfiguration } from "./configuration-manager";
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
ErpApiConnectionParams,
|
|
13
|
+
getErpApiConnectionParams,
|
|
14
|
+
} from "./configuration-manager";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { HashedCacheManager } from "../../caching-service/hashed-cache-manager";
|
|
3
|
+
import { SQLiteCoordinator } from "../../sqlite-service";
|
|
4
|
+
import logger from "../../../services/reporting-service/logger";
|
|
5
|
+
|
|
6
|
+
const main = async () => {
|
|
7
|
+
const cacheManager = new HashedCacheManager();
|
|
8
|
+
try {
|
|
9
|
+
logger.info('Worker for job "clean-up-expired-cache" online');
|
|
10
|
+
logger.info(
|
|
11
|
+
"==========Starting clean-up-expired-cache job cycle=========="
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
await SQLiteCoordinator.executeWithLock("clean-up-cache", async () => {
|
|
15
|
+
await cacheManager.removeExpiredObjects();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
logger.info(
|
|
19
|
+
"==========Completed clean-up-expired-cache job cycle=========="
|
|
20
|
+
);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
logger.error('Worker for job "clean-up-expired-cache" had an error', {
|
|
23
|
+
err: error,
|
|
24
|
+
});
|
|
25
|
+
throw error; // Rethrow so Bree can handle it properly
|
|
26
|
+
} finally {
|
|
27
|
+
await cacheManager.destroy();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// For Bree compatibility - check if this is running as a worker
|
|
32
|
+
if (require.main === module) {
|
|
33
|
+
// This is called when Bree runs this file as a worker
|
|
34
|
+
main();
|
|
35
|
+
} else {
|
|
36
|
+
// Export for potential testing or direct usage
|
|
37
|
+
module.exports = main;
|
|
38
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
|
|
3
|
+
import logger from "../../../services/reporting-service/logger";
|
|
4
|
+
import { SQLiteCoordinator } from "../../sqlite-service";
|
|
5
|
+
import { createConnectorFromPath } from "../../../utils/connector-factory";
|
|
6
|
+
|
|
7
|
+
const main = async () => {
|
|
8
|
+
try {
|
|
9
|
+
logger.info('Worker for job "from-erp" online');
|
|
10
|
+
logger.info("==========Starting from-erp job cycle==========");
|
|
11
|
+
|
|
12
|
+
// Get the connector path from the environment variable
|
|
13
|
+
const connectorPath = process.env.CONNECTOR_PATH;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if (!connectorPath) {
|
|
17
|
+
throw new Error("Connector path not provided in environment variables");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Create a new connector instance for this job
|
|
21
|
+
const connector = await createConnectorFromPath(connectorPath);
|
|
22
|
+
|
|
23
|
+
await SQLiteCoordinator.executeWithLock("from-erp", async () => {
|
|
24
|
+
await connector.syncFromERP();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await connector.syncFromERPCompleted();
|
|
28
|
+
logger.info("==========Completed from-erp job cycle==========");
|
|
29
|
+
} catch (error) {
|
|
30
|
+
const errorDetails = {
|
|
31
|
+
message: error instanceof Error ? error.message : String(error),
|
|
32
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
33
|
+
name: error instanceof Error ? error.name : undefined,
|
|
34
|
+
...(error && typeof error === "object" ? error : {}), // Include all enumerable properties if it's an object
|
|
35
|
+
};
|
|
36
|
+
logger.error('Worker for job "from-erp" had an error', {
|
|
37
|
+
error: errorDetails,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
throw error; // Rethrow so Bree can handle it properly
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// For Bree compatibility - check if this is running as a worker
|
|
45
|
+
// In ES modules, we need to check import.meta.url instead of require.main
|
|
46
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
47
|
+
|
|
48
|
+
if (isMainModule) {
|
|
49
|
+
// This is called when Bree runs this file as a worker
|
|
50
|
+
main().catch(() => {
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default main;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
|
|
3
|
+
import logger from "../../../services/reporting-service/logger";
|
|
4
|
+
import { createConnectorFromPath } from "../../../utils/connector-factory";
|
|
5
|
+
|
|
6
|
+
const main = async () => {
|
|
7
|
+
try {
|
|
8
|
+
logger.info('Worker for job "retry-failed-labor-tickets" online');
|
|
9
|
+
logger.info(
|
|
10
|
+
"==========Starting retry-failed-labor-tickets job cycle=========="
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
// Get the connector path from the environment variable
|
|
14
|
+
const connectorPath = process.env.CONNECTOR_PATH;
|
|
15
|
+
|
|
16
|
+
if (!connectorPath) {
|
|
17
|
+
throw new Error("Connector path not provided in environment variables");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Create a new connector instance for this job
|
|
21
|
+
const connector = await createConnectorFromPath(connectorPath);
|
|
22
|
+
|
|
23
|
+
await connector.retryFailedLaborTickets();
|
|
24
|
+
await connector.retryFailedLaborTicketsCompleted();
|
|
25
|
+
|
|
26
|
+
logger.info(
|
|
27
|
+
"==========Completed retry-failed-labor-tickets job cycle=========="
|
|
28
|
+
);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
logger.error('Worker for job "retry-failed-labor-tickets" had an error', {
|
|
31
|
+
err: error,
|
|
32
|
+
});
|
|
33
|
+
throw error; // Rethrow so Bree can handle it properly
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// For Bree compatibility - check if this is running as a worker
|
|
38
|
+
if (require.main === module) {
|
|
39
|
+
// This is called when Bree runs this file as a worker
|
|
40
|
+
main();
|
|
41
|
+
} else {
|
|
42
|
+
// Export for potential testing or direct usage
|
|
43
|
+
module.exports = main;
|
|
44
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import knex, { Knex } from "knex";
|
|
2
|
+
import logger from "../../reporting-service/logger";
|
|
3
|
+
import config from "../../../knexfile";
|
|
4
|
+
|
|
5
|
+
// MLW TODO Consider the location of knexfile
|
|
6
|
+
const db: Knex = knex(config.local);
|
|
7
|
+
|
|
8
|
+
export default async function runMigrations() {
|
|
9
|
+
try {
|
|
10
|
+
logger.info("Running migrations...");
|
|
11
|
+
await db.migrate.latest();
|
|
12
|
+
logger.info("Migrations complete!");
|
|
13
|
+
} catch (error) {
|
|
14
|
+
logger.error("Error running migrations:", error);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
} finally {
|
|
17
|
+
await db.destroy();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
runMigrations();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
|
|
3
|
+
import logger from "../../reporting-service/logger";
|
|
4
|
+
import { createConnectorFromPath } from "../../../utils/connector-factory";
|
|
5
|
+
|
|
6
|
+
const main = async () => {
|
|
7
|
+
try {
|
|
8
|
+
logger.info('Worker for job "to-erp" online');
|
|
9
|
+
logger.info("==========Starting to-erp job cycle==========");
|
|
10
|
+
|
|
11
|
+
// Get the connector path from the environment variable
|
|
12
|
+
const connectorPath = process.env.CONNECTOR_PATH;
|
|
13
|
+
|
|
14
|
+
if (!connectorPath) {
|
|
15
|
+
throw new Error("Connector path not provided in environment variables");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Create a new connector instance for this job
|
|
19
|
+
const connector = await createConnectorFromPath(connectorPath);
|
|
20
|
+
|
|
21
|
+
await connector.syncToERP();
|
|
22
|
+
await connector.syncToERPCompleted();
|
|
23
|
+
|
|
24
|
+
logger.info("==========Completed to-erp job cycle==========");
|
|
25
|
+
} catch (error) {
|
|
26
|
+
const errorDetails = {
|
|
27
|
+
message: error instanceof Error ? error.message : String(error),
|
|
28
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
29
|
+
name: error instanceof Error ? error.name : undefined,
|
|
30
|
+
...(error && typeof error === "object" ? error : {}), // Include all enumerable properties if it's an object
|
|
31
|
+
};
|
|
32
|
+
logger.error('Worker for job "to-erp" had an error', {
|
|
33
|
+
error: errorDetails,
|
|
34
|
+
connectorPath: process.env.CONNECTOR_PATH,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Also log to console for immediate visibility
|
|
38
|
+
console.error("to-erp job error:", error);
|
|
39
|
+
|
|
40
|
+
throw error; // Rethrow so Bree can handle it properly
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// For Bree compatibility - check if this is running as a worker
|
|
45
|
+
// In ES modules, we need to check import.meta.url instead of require.main
|
|
46
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
47
|
+
if (isMainModule) {
|
|
48
|
+
// This is called when Bree runs this file as a worker
|
|
49
|
+
main();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Export for potential testing or direct usage (ES module default export)
|
|
53
|
+
export default main;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { AxiosError } from "axios";
|
|
2
|
+
import logger from "../reporting-service/logger";
|
|
3
|
+
import { GraphQLServerError } from "./graphql/types";
|
|
4
|
+
import { HTTPError } from "../../utils/http-client";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents GraphQL specific errors (validation, missing fields, etc.)
|
|
8
|
+
*/
|
|
9
|
+
export class GraphQLError extends Error {
|
|
10
|
+
constructor(
|
|
11
|
+
message: string,
|
|
12
|
+
public errors: GraphQLServerError[]
|
|
13
|
+
) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "GraphQLError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Centralized error handling for API requests.
|
|
21
|
+
* Transforms various error types into standardized HTTPError or GraphQLError.
|
|
22
|
+
*/
|
|
23
|
+
export class ErrorHandler {
|
|
24
|
+
/**
|
|
25
|
+
* Transforms any error into a standardized HTTPError or GraphQLError and throws it.
|
|
26
|
+
* Never returns - always throws an error.
|
|
27
|
+
*
|
|
28
|
+
* @throws {HTTPError|GraphQLError} Standardized error with appropriate details
|
|
29
|
+
*/
|
|
30
|
+
static handle(error: unknown): never {
|
|
31
|
+
// Handle HTTPError (already processed by http-client)
|
|
32
|
+
if (error instanceof HTTPError) {
|
|
33
|
+
// For GraphQL responses with errors in the data
|
|
34
|
+
if (
|
|
35
|
+
error.data &&
|
|
36
|
+
typeof error.data === "object" &&
|
|
37
|
+
"errors" in error.data
|
|
38
|
+
) {
|
|
39
|
+
const graphqlError = new GraphQLError(
|
|
40
|
+
"GraphQL Error",
|
|
41
|
+
(error.data as { errors: GraphQLServerError[] }).errors
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// Log the error
|
|
45
|
+
logger.error("Error>>GraphQL", {
|
|
46
|
+
message: graphqlError.message,
|
|
47
|
+
errors: graphqlError.errors,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
throw graphqlError;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Log HTTP error with generic response data
|
|
54
|
+
logger.error("Error>>HTTP", {
|
|
55
|
+
status: error.status,
|
|
56
|
+
message: error.message,
|
|
57
|
+
code: error.code,
|
|
58
|
+
data: error.data,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
throw error; // Re-throw the original HTTPError
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Handle raw AxiosError (direct usage, not through http-client)
|
|
65
|
+
if (error instanceof AxiosError) {
|
|
66
|
+
// For GraphQL responses with errors
|
|
67
|
+
if (error.response?.data?.errors) {
|
|
68
|
+
const graphqlError = new GraphQLError(
|
|
69
|
+
"GraphQL Error",
|
|
70
|
+
error.response.data.errors as GraphQLServerError[]
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Log the error
|
|
74
|
+
logger.error("Error>>GraphQL", {
|
|
75
|
+
message: graphqlError.message,
|
|
76
|
+
errors: graphqlError.errors,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
throw graphqlError;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// For HTTP errors - create HTTPError and log with response data
|
|
83
|
+
const httpError = new HTTPError(
|
|
84
|
+
error.message,
|
|
85
|
+
error.response?.status || 500,
|
|
86
|
+
error.code,
|
|
87
|
+
error.response?.data
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Log HTTP error with generic response data
|
|
91
|
+
logger.error("Error>>HTTP", {
|
|
92
|
+
status: httpError.status,
|
|
93
|
+
message: httpError.message,
|
|
94
|
+
code: httpError.code,
|
|
95
|
+
data: httpError.data,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
throw httpError;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// For other errors
|
|
102
|
+
const httpError = new HTTPError(
|
|
103
|
+
error instanceof Error ? error.message : "An unknown error occurred",
|
|
104
|
+
500
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Log the error
|
|
108
|
+
logger.error("Error>>Unknown", {
|
|
109
|
+
message: httpError.message,
|
|
110
|
+
status: httpError.status,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
throw httpError;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HTTPClient,
|
|
3
|
+
HTTPClientFactory,
|
|
4
|
+
HTTPResponse,
|
|
5
|
+
} from "../../../utils/http-client";
|
|
6
|
+
import { GraphQLResponse } from "./types";
|
|
7
|
+
import { ErrorHandler } from "../errors";
|
|
8
|
+
import { APIResponse } from "../types";
|
|
9
|
+
import { ERPApiConfig } from "../types";
|
|
10
|
+
|
|
11
|
+
const DEFAULT_RETRY_ATTEMPTS = 0; // One try only, no retries
|
|
12
|
+
|
|
13
|
+
export class GraphQLService {
|
|
14
|
+
private client: HTTPClient;
|
|
15
|
+
private config: ERPApiConfig;
|
|
16
|
+
private endpoint: string;
|
|
17
|
+
|
|
18
|
+
constructor(config: ERPApiConfig, endpoint: string, retryAttempts?: number) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.endpoint = endpoint
|
|
21
|
+
? endpoint.startsWith("/")
|
|
22
|
+
? endpoint
|
|
23
|
+
: `/${endpoint}`
|
|
24
|
+
: "";
|
|
25
|
+
this.client = HTTPClientFactory.getInstance({
|
|
26
|
+
baseUrl: config.apiUrl,
|
|
27
|
+
retryAttempts: retryAttempts ?? DEFAULT_RETRY_ATTEMPTS,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private async getHeaders(): Promise<Record<string, string>> {
|
|
32
|
+
const token = await this.config.getAuthToken();
|
|
33
|
+
return {
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
Accept: "application/json",
|
|
36
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Handles a GraphQL response, properly handling both successful responses
|
|
42
|
+
* and GraphQL-level errors (which come in a 200 HTTP response)
|
|
43
|
+
*
|
|
44
|
+
* From the GraphQL specification (https://spec.graphql.org/draft/#sec-Errors):
|
|
45
|
+
> * "When a GraphQL server encounters an error, it should return a response with a
|
|
46
|
+
> * top-level "errors" field containing the error information. The response may still contain
|
|
47
|
+
* a partial result in the "data" field if the error occurred after some data was already resolved."
|
|
48
|
+
*
|
|
49
|
+
* And specifically about HTTP status codes:
|
|
50
|
+
* "A server should return a 200 status code when a GraphQL operation successfully executes, including when
|
|
51
|
+
* the operation returns errors. A server should return a 400 status code when a GraphQL operation fails to execute."
|
|
52
|
+
*/
|
|
53
|
+
private handleGraphQLResponse<T>(
|
|
54
|
+
response: HTTPResponse<GraphQLResponse<T>>
|
|
55
|
+
): APIResponse<T> {
|
|
56
|
+
return {
|
|
57
|
+
data: response.data.data as T,
|
|
58
|
+
metadata: {
|
|
59
|
+
errors: response.data.errors,
|
|
60
|
+
extensions: response.data.extensions,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Executes a GraphQL query
|
|
67
|
+
* @param query The GraphQL query string
|
|
68
|
+
* @param variables Optional variables for the query
|
|
69
|
+
* @returns The query result
|
|
70
|
+
* @throws {HTTPError} For HTTP/network errors only
|
|
71
|
+
*/
|
|
72
|
+
async query<T>(
|
|
73
|
+
query: string,
|
|
74
|
+
variables?: Record<string, unknown>
|
|
75
|
+
): Promise<APIResponse<T>> {
|
|
76
|
+
try {
|
|
77
|
+
const headers = await this.getHeaders();
|
|
78
|
+
const response = await this.client.request<GraphQLResponse<T>>({
|
|
79
|
+
method: "POST",
|
|
80
|
+
url: this.endpoint,
|
|
81
|
+
data: { query, variables },
|
|
82
|
+
headers,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return this.handleGraphQLResponse(response);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
ErrorHandler.handle(error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Executes a GraphQL mutation
|
|
93
|
+
* @param mutation The GraphQL mutation string
|
|
94
|
+
* @param variables Optional variables for the mutation
|
|
95
|
+
* @returns The mutation result
|
|
96
|
+
* @throws {HTTPError} For HTTP/network errors only
|
|
97
|
+
*/
|
|
98
|
+
async mutate<T>(
|
|
99
|
+
mutation: string,
|
|
100
|
+
variables?: Record<string, unknown>
|
|
101
|
+
): Promise<APIResponse<T>> {
|
|
102
|
+
try {
|
|
103
|
+
const headers = await this.getHeaders();
|
|
104
|
+
const response = await this.client.request<GraphQLResponse<T>>({
|
|
105
|
+
method: "POST",
|
|
106
|
+
url: this.endpoint,
|
|
107
|
+
data: { query: mutation, variables },
|
|
108
|
+
headers,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return this.handleGraphQLResponse(response);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
ErrorHandler.handle(error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base GraphQL response type that matches the GraphQL specification.
|
|
3
|
+
* Note that pagination styles are server-specific and should be defined by each connector.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This represents an error from the GraphQL server, described here: https://spec.graphql.org/draft/#sec-Errors
|
|
8
|
+
*/
|
|
9
|
+
export interface GraphQLServerError {
|
|
10
|
+
/** A description of the error */
|
|
11
|
+
message: string;
|
|
12
|
+
/** Locations in the query where the error occurred */
|
|
13
|
+
locations?: { line: number; column: number }[];
|
|
14
|
+
/** Path to the field that caused the error */
|
|
15
|
+
path?: (string | number)[];
|
|
16
|
+
/** Additional error information */
|
|
17
|
+
extensions?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The standard GraphQL response format as per the GraphQL spec: https://spec.graphql.org/draft/#sec-Response-Format
|
|
22
|
+
*/
|
|
23
|
+
export interface GraphQLResponse<T> {
|
|
24
|
+
/** The actual response data, or null if there were errors */
|
|
25
|
+
data: T | null;
|
|
26
|
+
/** Array of errors if any occurred */
|
|
27
|
+
errors?: GraphQLServerError[];
|
|
28
|
+
/** Optional extensions to the response */
|
|
29
|
+
extensions?: Record<string, unknown>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ERP API Services for the MachineMetrics ERP Connector SDK.
|
|
3
|
+
* This file exports the public interfaces and types for ERP API services.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// REST API Service
|
|
7
|
+
export { RestAPIService } from "./rest/rest-api-service";
|
|
8
|
+
export type { QueryParams } from "./rest/get-query-params";
|
|
9
|
+
|
|
10
|
+
// GraphQL Service
|
|
11
|
+
export { GraphQLService } from "./graphql/graphql-service";
|
|
12
|
+
|
|
13
|
+
// OAuth Client
|
|
14
|
+
export { OAuthClient } from "./oauth-client";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for OAuth client credentials flow
|
|
3
|
+
*/
|
|
4
|
+
export interface OAuthConfig {
|
|
5
|
+
/** The URL to request the OAuth token from */
|
|
6
|
+
authUrl: string;
|
|
7
|
+
/** The client ID for OAuth authentication */
|
|
8
|
+
clientId: string;
|
|
9
|
+
/** The client secret for OAuth authentication */
|
|
10
|
+
clientSecret: string;
|
|
11
|
+
/** The scope for the OAuth token. Use empty string if no scope is needed. */
|
|
12
|
+
scope: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Standard OAuth 2.0 token response format as defined in RFC 6749
|
|
17
|
+
*/
|
|
18
|
+
export interface OAuthTokenResponse {
|
|
19
|
+
/** The access token issued by the authorization server */
|
|
20
|
+
access_token: string;
|
|
21
|
+
/** The type of token issued (typically "Bearer") */
|
|
22
|
+
token_type: string;
|
|
23
|
+
/** The lifetime in seconds of the access token */
|
|
24
|
+
expires_in: number;
|
|
25
|
+
/** The refresh token, which can be used to obtain new access tokens (optional) */
|
|
26
|
+
refresh_token?: string;
|
|
27
|
+
/** The scope of the access token (optional) */
|
|
28
|
+
scope?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A utility class for handling OAuth client credentials flow.
|
|
33
|
+
* This is specifically for the client credentials grant type,
|
|
34
|
+
* which is used for server-to-server authentication.
|
|
35
|
+
*/
|
|
36
|
+
export class OAuthClient {
|
|
37
|
+
constructor(private config: OAuthConfig) {}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Requests an OAuth token using the client credentials flow.
|
|
41
|
+
* The request is sent as application/x-www-form-urlencoded.
|
|
42
|
+
* @returns A promise that resolves to the token response containing access_token and expires_in
|
|
43
|
+
* @throws Error if the token request fails
|
|
44
|
+
*/
|
|
45
|
+
async getToken(): Promise<OAuthTokenResponse> {
|
|
46
|
+
const formData = new URLSearchParams({
|
|
47
|
+
grant_type: "client_credentials",
|
|
48
|
+
client_id: this.config.clientId,
|
|
49
|
+
client_secret: this.config.clientSecret,
|
|
50
|
+
scope: this.config.scope,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const response = await fetch(this.config.authUrl, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
57
|
+
},
|
|
58
|
+
body: formData,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
throw new Error(`OAuth token request failed: ${response.statusText}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const data = (await response.json()) as OAuthTokenResponse;
|
|
66
|
+
if (data.token_type !== "Bearer") {
|
|
67
|
+
throw new Error(`Unexpected token type: ${data.token_type}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
72
|
+
}
|