ofsc-utility 1.0.20 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/events/index.d.ts
CHANGED
|
@@ -1,9 +1,44 @@
|
|
|
1
1
|
type AnyObject = {
|
|
2
2
|
[key: string]: any;
|
|
3
3
|
};
|
|
4
|
+
/**
|
|
5
|
+
* Recursively flattens an object into a single-level object with
|
|
6
|
+
* underscore-separated keys.
|
|
7
|
+
*
|
|
8
|
+
* Example: { a: { b: 1 } } -> { "a_b": 1 }
|
|
9
|
+
*
|
|
10
|
+
* Usage: exported helper used when callers need a flat row-style
|
|
11
|
+
* representation (e.g., CSV export). Not used internally in this
|
|
12
|
+
* module but available for other modules to import.
|
|
13
|
+
*
|
|
14
|
+
* @param obj - The object to flatten.
|
|
15
|
+
* @param parentKey - Internal recursion prefix (do not pass normally).
|
|
16
|
+
* @param result - Internal accumulator (do not pass normally).
|
|
17
|
+
* @returns The flattened object.
|
|
18
|
+
*/
|
|
4
19
|
export declare function flattenObject(obj: AnyObject, parentKey?: string, result?: AnyObject): AnyObject;
|
|
5
20
|
export declare function downloadAllEventsOfDay(clientId: string, clientSecret: string, instanceUrl: string, subscriptionId: string, sinceDate: string, onlyData: boolean): Promise<any[]>;
|
|
6
21
|
export declare function downloadAllEventsOfDayCSV(clientId: string, clientSecret: string, instanceUrl: string, subscriptionId: string, sinceDate: string, onlyData: boolean): Promise<any[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Generate a deterministic SHA-256 hash for an event item.
|
|
24
|
+
*
|
|
25
|
+
* This uses a stable stringification of the selected fields so that
|
|
26
|
+
* object property ordering does not change the resulting hash. Useful
|
|
27
|
+
* for deduplication or consistent event identity across runs.
|
|
28
|
+
*
|
|
29
|
+
* @param item - Object containing `eventType`, `activityId`, `time`, and `activityChanges`.
|
|
30
|
+
* @returns Hex-encoded SHA-256 hash string representing the event.
|
|
31
|
+
*/
|
|
32
|
+
export declare function generateHash(item: {
|
|
33
|
+
eventType: string;
|
|
34
|
+
activityId: string | number;
|
|
35
|
+
time: string;
|
|
36
|
+
activityChanges: unknown;
|
|
37
|
+
inventoryChanges?: unknown;
|
|
38
|
+
resourceDetails: {
|
|
39
|
+
resourceId: string | number;
|
|
40
|
+
};
|
|
41
|
+
}): string;
|
|
7
42
|
/**
|
|
8
43
|
* Events of last two minutes
|
|
9
44
|
* @param clientId
|
package/dist/events/index.js
CHANGED
|
@@ -6,11 +6,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.flattenObject = flattenObject;
|
|
7
7
|
exports.downloadAllEventsOfDay = downloadAllEventsOfDay;
|
|
8
8
|
exports.downloadAllEventsOfDayCSV = downloadAllEventsOfDayCSV;
|
|
9
|
+
exports.generateHash = generateHash;
|
|
9
10
|
exports.downloadAllEventsOfDLastTwoMinutes = downloadAllEventsOfDLastTwoMinutes;
|
|
11
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
10
12
|
const path_1 = __importDefault(require("path"));
|
|
11
13
|
const index_1 = require("../oauthTokenService/index");
|
|
12
14
|
const utilities_1 = require("../utilities");
|
|
13
15
|
const index_2 = require("../utilities/index");
|
|
16
|
+
/**
|
|
17
|
+
* Recursively flattens an object into a single-level object with
|
|
18
|
+
* underscore-separated keys.
|
|
19
|
+
*
|
|
20
|
+
* Example: { a: { b: 1 } } -> { "a_b": 1 }
|
|
21
|
+
*
|
|
22
|
+
* Usage: exported helper used when callers need a flat row-style
|
|
23
|
+
* representation (e.g., CSV export). Not used internally in this
|
|
24
|
+
* module but available for other modules to import.
|
|
25
|
+
*
|
|
26
|
+
* @param obj - The object to flatten.
|
|
27
|
+
* @param parentKey - Internal recursion prefix (do not pass normally).
|
|
28
|
+
* @param result - Internal accumulator (do not pass normally).
|
|
29
|
+
* @returns The flattened object.
|
|
30
|
+
*/
|
|
14
31
|
function flattenObject(obj, parentKey = "", result = {}) {
|
|
15
32
|
for (const key in obj) {
|
|
16
33
|
const newKey = parentKey ? `${parentKey}_${key}` : key;
|
|
@@ -25,6 +42,21 @@ function flattenObject(obj, parentKey = "", result = {}) {
|
|
|
25
42
|
}
|
|
26
43
|
return result;
|
|
27
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Fetch a single page of events via `fetchWithRetry` and return the
|
|
47
|
+
* received token and typed `EventResponse` data.
|
|
48
|
+
*
|
|
49
|
+
* This is a small wrapper around `fetchWithRetry` that normalizes the
|
|
50
|
+
* response shape for the callers in this module. It is used by both
|
|
51
|
+
* `downloadAllEventsOfDayCSV` and `downloadAllEventsOfDLastTwoMinutes`.
|
|
52
|
+
*
|
|
53
|
+
* @param url - Full URL for the events endpoint page.
|
|
54
|
+
* @param token - Current OAuth token (may be refreshed by fetchWithRetry).
|
|
55
|
+
* @param clientId - OAuth client id used by `fetchWithRetry` if token refresh needed.
|
|
56
|
+
* @param clientSecret - OAuth client secret used by `fetchWithRetry`.
|
|
57
|
+
* @param instanceUrl - Instance host used by `fetchWithRetry`.
|
|
58
|
+
* @returns Object with `token` (possibly refreshed) and `data` typed as `EventResponse`.
|
|
59
|
+
*/
|
|
28
60
|
async function fetchEventsPage(url, token, clientId, clientSecret, instanceUrl) {
|
|
29
61
|
const res = await (0, utilities_1.fetchWithRetry)(url, clientId, clientSecret, instanceUrl, token);
|
|
30
62
|
return {
|
|
@@ -32,6 +64,17 @@ async function fetchEventsPage(url, token, clientId, clientSecret, instanceUrl)
|
|
|
32
64
|
data: res.data
|
|
33
65
|
};
|
|
34
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Return the next calendar day in `YYYY-MM-DD` format for a given
|
|
69
|
+
* `YYYY-MM-DD` input string.
|
|
70
|
+
*
|
|
71
|
+
* Usage: used by `processEventItems` to detect when fetched event
|
|
72
|
+
* pages cross into the following day, allowing the downloader to stop
|
|
73
|
+
* collecting events for the requested date.
|
|
74
|
+
*
|
|
75
|
+
* @param dateString - Date string in `YYYY-MM-DD` form.
|
|
76
|
+
* @returns Date string for the next day in `YYYY-MM-DD`.
|
|
77
|
+
*/
|
|
35
78
|
function getNextDay(dateString) {
|
|
36
79
|
// Parse manually to avoid timezone issues
|
|
37
80
|
const [year, month, day] = dateString.split('-').map(Number);
|
|
@@ -43,6 +86,25 @@ function getNextDay(dateString) {
|
|
|
43
86
|
const d = pad(date.getDate());
|
|
44
87
|
return `${y}-${m}-${d}`;
|
|
45
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Process an array of event items and push them into `output` while
|
|
91
|
+
* enforcing a date boundary.
|
|
92
|
+
*
|
|
93
|
+
* Behavior:
|
|
94
|
+
* - If an event's `time` indicates it belongs to the next calendar
|
|
95
|
+
* day (based on `sinceDate`) the function logs and returns `false`
|
|
96
|
+
* to signal the caller to stop pagination.
|
|
97
|
+
* - Otherwise, it extracts `activityId` from `activityDetails` and
|
|
98
|
+
* pushes a top-level object into `output`.
|
|
99
|
+
*
|
|
100
|
+
* Usage: called from `downloadAllEventsOfDayCSV` during page
|
|
101
|
+
* iteration to accumulate events for the requested date.
|
|
102
|
+
*
|
|
103
|
+
* @param items - Event items from a page response.
|
|
104
|
+
* @param sinceDate - The starting date (YYYY-MM-DD) used to detect day boundaries.
|
|
105
|
+
* @param output - Accumulator array to receive processed events.
|
|
106
|
+
* @returns `true` to continue pagination, `false` to stop.
|
|
107
|
+
*/
|
|
46
108
|
function processEventItems(items, sinceDate, output) {
|
|
47
109
|
for (const item of items) {
|
|
48
110
|
const eventTime = item.time;
|
|
@@ -59,10 +121,37 @@ function processEventItems(items, sinceDate, output) {
|
|
|
59
121
|
}
|
|
60
122
|
async function downloadAllEventsOfDay(clientId, clientSecret, instanceUrl, subscriptionId, sinceDate, onlyData) {
|
|
61
123
|
console.log("Downloading events...OnlyData:", onlyData);
|
|
124
|
+
// Convenience wrapper: returns the same data as
|
|
125
|
+
// `downloadAllEventsOfDayCSV` but kept as a separate exported
|
|
126
|
+
// function for readability and future extension.
|
|
62
127
|
let data = await downloadAllEventsOfDayCSV(clientId, clientSecret, instanceUrl, subscriptionId, sinceDate, onlyData);
|
|
63
128
|
return data;
|
|
64
129
|
}
|
|
65
130
|
async function downloadAllEventsOfDayCSV(clientId, clientSecret, instanceUrl, subscriptionId, sinceDate, onlyData) {
|
|
131
|
+
/**
|
|
132
|
+
* Download all events for a specific calendar day and return them as an
|
|
133
|
+
* array. Internally handles pagination and will stop when pages cross
|
|
134
|
+
* into the next day.
|
|
135
|
+
*
|
|
136
|
+
* Key behaviors and usage:
|
|
137
|
+
* - Builds an initial request for the given `sinceDate` and pages
|
|
138
|
+
* through results using `fetchEventsPage`.
|
|
139
|
+
* - Uses `processEventItems` to add items to the `events` array and
|
|
140
|
+
* stop when the date boundary is reached.
|
|
141
|
+
* - If `onlyData` is false the collected events are saved to a CSV on
|
|
142
|
+
* disk via `saveCsv`.
|
|
143
|
+
*
|
|
144
|
+
* Called by: `downloadAllEventsOfDay` (simple wrapper) and can be
|
|
145
|
+
* imported directly by other modules that need the raw event list.
|
|
146
|
+
*
|
|
147
|
+
* @param clientId - OAuth client id for token operations.
|
|
148
|
+
* @param clientSecret - OAuth client secret for token operations.
|
|
149
|
+
* @param instanceUrl - Instance host used to construct the endpoint.
|
|
150
|
+
* @param subscriptionId - Events subscription id to fetch.
|
|
151
|
+
* @param sinceDate - Date string in `YYYY-MM-DD` to fetch events for.
|
|
152
|
+
* @param onlyData - When true, skip saving CSV to disk and return data only.
|
|
153
|
+
* @returns Array of event objects collected for the requested date.
|
|
154
|
+
*/
|
|
66
155
|
// All collected events
|
|
67
156
|
const events = [];
|
|
68
157
|
// Build initial request URL
|
|
@@ -126,6 +215,52 @@ async function downloadAllEventsOfDayCSV(clientId, clientSecret, instanceUrl, su
|
|
|
126
215
|
}
|
|
127
216
|
return events;
|
|
128
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Deterministically stringify a value for stable hashing.
|
|
220
|
+
*
|
|
221
|
+
* - Sorts object keys so property order does not affect output.
|
|
222
|
+
* - Recursively processes arrays and objects.
|
|
223
|
+
* - Falls back to `JSON.stringify` for primitive values.
|
|
224
|
+
*
|
|
225
|
+
* This is used by `generateHash` to produce a stable representation
|
|
226
|
+
* of event payloads before hashing.
|
|
227
|
+
*
|
|
228
|
+
* @param value - The value to stringify (object, array, or primitive).
|
|
229
|
+
* @returns A deterministic string representation of `value`.
|
|
230
|
+
*/
|
|
231
|
+
function stableStringify(value) {
|
|
232
|
+
if (Array.isArray(value)) {
|
|
233
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
234
|
+
}
|
|
235
|
+
if (value && typeof value === "object") {
|
|
236
|
+
return `{${Object.keys(value)
|
|
237
|
+
.sort()
|
|
238
|
+
.map(key => `"${key}":${stableStringify(value[key])}`)
|
|
239
|
+
.join(",")}}`;
|
|
240
|
+
}
|
|
241
|
+
return JSON.stringify(value);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Generate a deterministic SHA-256 hash for an event item.
|
|
245
|
+
*
|
|
246
|
+
* This uses a stable stringification of the selected fields so that
|
|
247
|
+
* object property ordering does not change the resulting hash. Useful
|
|
248
|
+
* for deduplication or consistent event identity across runs.
|
|
249
|
+
*
|
|
250
|
+
* @param item - Object containing `eventType`, `activityId`, `time`, and `activityChanges`.
|
|
251
|
+
* @returns Hex-encoded SHA-256 hash string representing the event.
|
|
252
|
+
*/
|
|
253
|
+
function generateHash(item) {
|
|
254
|
+
return node_crypto_1.default
|
|
255
|
+
.createHash("sha256")
|
|
256
|
+
.update(stableStringify({
|
|
257
|
+
eventType: item.eventType,
|
|
258
|
+
activityId: item.activityId || item.resourceDetails.resourceId,
|
|
259
|
+
time: item.time,
|
|
260
|
+
activityChanges: item.activityChanges || item.inventoryChanges || {},
|
|
261
|
+
}))
|
|
262
|
+
.digest("hex");
|
|
263
|
+
}
|
|
129
264
|
/**
|
|
130
265
|
* Events of last two minutes
|
|
131
266
|
* @param clientId
|
|
@@ -135,6 +270,25 @@ async function downloadAllEventsOfDayCSV(clientId, clientSecret, instanceUrl, su
|
|
|
135
270
|
* @returns
|
|
136
271
|
*/
|
|
137
272
|
async function downloadAllEventsOfDLastTwoMinutes(clientId, clientSecret, instanceUrl, subscriptionId) {
|
|
273
|
+
/**
|
|
274
|
+
* Download events from the last ~180 seconds and return them as an
|
|
275
|
+
* array.
|
|
276
|
+
*
|
|
277
|
+
* Differences from `downloadAllEventsOfDayCSV`:
|
|
278
|
+
* - The `since` timestamp is computed using `getTimeBefore180SecondsAlt`.
|
|
279
|
+
* - Validates the generated timestamp with `validateDateTimeStrict`.
|
|
280
|
+
* - For each fetched item, this function attaches a `uniqueId` field
|
|
281
|
+
* generated by `generateHash` (used for deduplication or tracing).
|
|
282
|
+
*
|
|
283
|
+
* Usage: lightweight polling helper to retrieve recent events for
|
|
284
|
+
* short-lived processing or monitoring.
|
|
285
|
+
*
|
|
286
|
+
* @param clientId - OAuth client id.
|
|
287
|
+
* @param clientSecret - OAuth client secret.
|
|
288
|
+
* @param instanceUrl - Instance host.
|
|
289
|
+
* @param subscriptionId - Subscription id for events.
|
|
290
|
+
* @returns Array of recent event objects.
|
|
291
|
+
*/
|
|
138
292
|
// All collected events
|
|
139
293
|
const events = [];
|
|
140
294
|
const since = (0, index_2.getTimeBefore180SecondsAlt)();
|
|
@@ -173,8 +327,8 @@ async function downloadAllEventsOfDLastTwoMinutes(clientId, clientSecret, instan
|
|
|
173
327
|
// Prevent infinite looping
|
|
174
328
|
if (nextPage === lastSeenPage) {
|
|
175
329
|
repeatedPageCount++;
|
|
176
|
-
if (repeatedPageCount >
|
|
177
|
-
console.warn("⚠️ Pagination repeating same page more than
|
|
330
|
+
if (repeatedPageCount > 15) {
|
|
331
|
+
console.warn("⚠️ Pagination repeating same page more than 15 times. Stopping.");
|
|
178
332
|
break;
|
|
179
333
|
}
|
|
180
334
|
}
|
|
@@ -188,6 +342,9 @@ async function downloadAllEventsOfDLastTwoMinutes(clientId, clientSecret, instan
|
|
|
188
342
|
break;
|
|
189
343
|
}
|
|
190
344
|
for (let k of page.items) {
|
|
345
|
+
k["uniqueId"] = generateHash(k);
|
|
346
|
+
k["Change"] = k.activityChanges || k.inventoryChanges || {};
|
|
347
|
+
k["Id"] = k.activityId || k.resourceDetails?.resourceId || '-';
|
|
191
348
|
events.push(k);
|
|
192
349
|
}
|
|
193
350
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example script to fetch events using the `src/events` helpers.
|
|
3
|
+
*
|
|
4
|
+
* This copy lives under `src/` so `tsc` will emit it into `dist/scripts/`.
|
|
5
|
+
*
|
|
6
|
+
* Environment variables:
|
|
7
|
+
* - CLIENT_ID
|
|
8
|
+
* - CLIENT_SECRET
|
|
9
|
+
* - INSTANCE_URL (host portion, e.g. example-instance)
|
|
10
|
+
* - SUBSCRIPTION_ID
|
|
11
|
+
* - SINCE_DATE (optional) - YYYY-MM-DD to fetch a full day's events
|
|
12
|
+
* - ONLY_DATA (optional) - when "true", skip saving CSV in downloader
|
|
13
|
+
*
|
|
14
|
+
compile + run:
|
|
15
|
+
* tsc && node dist/events/scripts/fetch-events-example.js
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Example script to fetch events using the `src/events` helpers.
|
|
4
|
+
*
|
|
5
|
+
* This copy lives under `src/` so `tsc` will emit it into `dist/scripts/`.
|
|
6
|
+
*
|
|
7
|
+
* Environment variables:
|
|
8
|
+
* - CLIENT_ID
|
|
9
|
+
* - CLIENT_SECRET
|
|
10
|
+
* - INSTANCE_URL (host portion, e.g. example-instance)
|
|
11
|
+
* - SUBSCRIPTION_ID
|
|
12
|
+
* - SINCE_DATE (optional) - YYYY-MM-DD to fetch a full day's events
|
|
13
|
+
* - ONLY_DATA (optional) - when "true", skip saving CSV in downloader
|
|
14
|
+
*
|
|
15
|
+
compile + run:
|
|
16
|
+
* tsc && node dist/events/scripts/fetch-events-example.js
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
const __1 = require("..");
|
|
20
|
+
const clientId = process.env.CLIENT_ID;
|
|
21
|
+
const clientSecret = process.env.CLIENT_SECRET;
|
|
22
|
+
const instanceUrl = process.env.INSTANCE_URL;
|
|
23
|
+
const subscriptionId = process.env.SUBSCRIPTION_ID;
|
|
24
|
+
if (!clientId || !clientSecret || !instanceUrl || !subscriptionId) {
|
|
25
|
+
console.error("Missing required env vars: CLIENT_ID, CLIENT_SECRET, INSTANCE_URL, SUBSCRIPTION_ID");
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
(async () => {
|
|
29
|
+
try {
|
|
30
|
+
if (process.env.SINCE_DATE) {
|
|
31
|
+
const sinceDate = process.env.SINCE_DATE;
|
|
32
|
+
const onlyData = process.env.ONLY_DATA === "true";
|
|
33
|
+
console.log(`Fetching events for day ${sinceDate}...`);
|
|
34
|
+
const events = await (0, __1.downloadAllEventsOfDayCSV)(clientId, clientSecret, instanceUrl, subscriptionId, sinceDate, onlyData);
|
|
35
|
+
console.log(`Fetched ${events.length} events for ${sinceDate}`);
|
|
36
|
+
if (events.length > 0)
|
|
37
|
+
console.log("Sample:", events[0]);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.log("Fetching events from last ~180 seconds...");
|
|
41
|
+
const recent = await (0, __1.downloadAllEventsOfDLastTwoMinutes)(clientId, clientSecret, instanceUrl, subscriptionId);
|
|
42
|
+
console.log(`Fetched ${recent.length} recent events`);
|
|
43
|
+
if (recent.length > 0)
|
|
44
|
+
console.log("Sample:", recent[0]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
console.error("Error fetching events:", err);
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofsc-utility",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "A wrapper for Oracle Field Service REST API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -45,10 +45,11 @@
|
|
|
45
45
|
"typescript": "^5.9.3"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
+
"dotenv": "^17.4.2",
|
|
48
49
|
"node-fetch": "^2.7.0",
|
|
49
50
|
"tslib": "^2.8.1",
|
|
50
51
|
"xlsx": "^0.18.5",
|
|
51
52
|
"xlsx-js-style": "^1.2.0",
|
|
52
53
|
"xmldom": "^0.6.0"
|
|
53
54
|
}
|
|
54
|
-
}
|
|
55
|
+
}
|