ofsc-utility 1.0.47 → 1.0.49

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
@@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
10
10
  - version 1.0.46
11
11
 
12
12
  ### Added
13
+ - add user management methods for standalone OFSC
14
+ - Update version and add resource management APIs
15
+ - version 1.0.47 and add resource APIs
13
16
  - release v1.0.44 with getResource function and updated keywords
14
17
  - version 1.0.43 with built-in resilience and exponential backoff
15
18
  - Add -c flag to skip CHANGELOG updates and auto-update logic
@@ -6,3 +6,4 @@ export declare function getworkSkillsOfResource(clientId: string, clientSecret:
6
6
  data: any;
7
7
  }>;
8
8
  export declare function getResourcebyId(resourceId: string, clientId: string, clientSecret: string, instanceUrl: string, initialToken?: string): Promise<ResourceResponse>;
9
+ export declare function updateResourcebyId(resourceId: string, clientId: string, clientSecret: string, instanceUrl: string, initialToken: string | undefined, payload: {}): Promise<ResourceResponse>;
@@ -40,6 +40,7 @@ exports.downloadAllResourcesCSV = downloadAllResourcesCSV;
40
40
  exports.AllResources = AllResources;
41
41
  exports.getworkSkillsOfResource = getworkSkillsOfResource;
42
42
  exports.getResourcebyId = getResourcebyId;
43
+ exports.updateResourcebyId = updateResourcebyId;
43
44
  const fs = __importStar(require("fs"));
44
45
  const node_fetch_1 = __importDefault(require("node-fetch"));
45
46
  const index_1 = require("../oauthTokenService/index");
@@ -149,3 +150,11 @@ async function getResourcebyId(resourceId, clientId, clientSecret, instanceUrl,
149
150
  };
150
151
  return fetchResources(0, initialToken);
151
152
  }
153
+ async function updateResourcebyId(resourceId, clientId, clientSecret, instanceUrl, initialToken = "", payload) {
154
+ const fetchResources = async (offset, token) => {
155
+ const url = `https://${instanceUrl}.fs.ocs.oraclecloud.com/rest/ofscCore/v1/resources/${encodeURIComponent(resourceId)}`;
156
+ const res = await (0, utilities_1.fetchPatchWithRetry)(url, clientId, clientSecret, instanceUrl, token, payload);
157
+ return res.data;
158
+ };
159
+ return fetchResources(0, initialToken);
160
+ }
@@ -1,3 +1,4 @@
1
+ import { ResourceResponse } from "../types";
1
2
  export declare function downloadAllUsersCSV(clientId: string, clientSecret: string, instanceUrl: string): Promise<void>;
2
3
  export { generateUsersCollaborationCSV } from './collaborationGroups';
3
4
  declare const OfscUserUtility: {
@@ -5,7 +6,10 @@ declare const OfscUserUtility: {
5
6
  downloadAllUsersCSV: typeof downloadAllUsersCSV;
6
7
  downloadAllInactiveUsersCSV: typeof downloadAllInactiveUsersCSV;
7
8
  downloadAllInactiveUsers: typeof downloadAllInactiveUsers;
9
+ getUserByLogin: typeof getUserByLogin;
8
10
  };
9
11
  export declare function downloadAllInactiveUsersCSV(clientId: string, clientSecret: string, instanceUrl: string, inactivityThresholdDays?: number): Promise<void>;
10
12
  export declare function downloadAllInactiveUsers(clientId: string, clientSecret: string, instanceUrl: string, inactivityThresholdDays?: number): Promise<Record<string, any>[]>;
13
+ export declare function getUserByLogin(login: string, clientId: string, clientSecret: string, instanceUrl: string, initialToken?: string): Promise<any>;
14
+ export declare function updateUserbyLogin(login: string, clientId: string, clientSecret: string, instanceUrl: string, initialToken: string | undefined, payload: {}): Promise<ResourceResponse>;
11
15
  export default OfscUserUtility;
@@ -40,6 +40,8 @@ exports.generateUsersCollaborationCSV = void 0;
40
40
  exports.downloadAllUsersCSV = downloadAllUsersCSV;
41
41
  exports.downloadAllInactiveUsersCSV = downloadAllInactiveUsersCSV;
42
42
  exports.downloadAllInactiveUsers = downloadAllInactiveUsers;
43
+ exports.getUserByLogin = getUserByLogin;
44
+ exports.updateUserbyLogin = updateUserbyLogin;
43
45
  const fs = __importStar(require("fs"));
44
46
  const node_fetch_1 = __importDefault(require("node-fetch"));
45
47
  const index_1 = require("../oauthTokenService/index");
@@ -123,7 +125,8 @@ const OfscUserUtility = {
123
125
  generateUsersCollaborationCSV: require('./collaborationGroups').generateUsersCollaborationCSV,
124
126
  downloadAllUsersCSV,
125
127
  downloadAllInactiveUsersCSV,
126
- downloadAllInactiveUsers
128
+ downloadAllInactiveUsers,
129
+ getUserByLogin
127
130
  };
128
131
  /**
129
132
  * Returns true if the user is "inactive":
@@ -292,4 +295,21 @@ async function downloadAllInactiveUsers(clientId, clientSecret, instanceUrl, ina
292
295
  console.log("-------------------------------------");
293
296
  return result;
294
297
  }
298
+ // /rest/ofscCore/v1/users/{login}
299
+ async function getUserByLogin(login, clientId, clientSecret, instanceUrl, initialToken = "") {
300
+ const fetchUser = async (offset, token) => {
301
+ const url = `https://${instanceUrl}.fs.ocs.oraclecloud.com/rest/ofscCore/v1/users/${encodeURIComponent(login)}?offset=${offset}&limit=100`;
302
+ const res = await (0, index_2.fetchWithRetry)(url, clientId, clientSecret, instanceUrl, token);
303
+ return res.data;
304
+ };
305
+ return fetchUser(0, initialToken);
306
+ }
307
+ async function updateUserbyLogin(login, clientId, clientSecret, instanceUrl, initialToken = "", payload) {
308
+ const fetchUser = async (offset, token) => {
309
+ const url = `https://${instanceUrl}.fs.ocs.oraclecloud.com/rest/ofscCore/v1/users/${encodeURIComponent(login)}`;
310
+ const res = await (0, index_2.fetchPatchWithRetry)(url, clientId, clientSecret, instanceUrl, token, payload);
311
+ return res.data;
312
+ };
313
+ return fetchUser(0, initialToken);
314
+ }
295
315
  exports.default = OfscUserUtility;
@@ -13,6 +13,14 @@ export declare const fetchWithRetry: (url: string, clientId: string, clientSecre
13
13
  data: any;
14
14
  token: string;
15
15
  }>;
16
+ export declare const fetchPatchWithRetry: (url: string, clientId: string, clientSecret: string, instanceUrl: string, token: string, body: any, retries?: number, baseDelay?: number) => Promise<{
17
+ data: any;
18
+ token: string;
19
+ }>;
20
+ export declare const fetchPostWithRetry: (url: string, clientId: string, clientSecret: string, instanceUrl: string, token: string, body: any, retries?: number, baseDelay?: number) => Promise<{
21
+ data: any;
22
+ token: string;
23
+ }>;
16
24
  export declare function saveCsv<T extends Record<string, any>>(rows: T[], filePath: string): void;
17
25
  export declare function xmlNodeToObjects(xmlString: string, parentNodeName: string): Record<string, string>[];
18
26
  type SheetRow = Record<string, unknown>;
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.fetchWithRetry = void 0;
39
+ exports.fetchPostWithRetry = exports.fetchPatchWithRetry = exports.fetchWithRetry = void 0;
40
40
  exports.saveCsv = saveCsv;
41
41
  exports.xmlNodeToObjects = xmlNodeToObjects;
42
42
  exports.createExcelFile = createExcelFile;
@@ -122,6 +122,138 @@ const fetchWithRetry = async (url, clientId, clientSecret, instanceUrl, token, r
122
122
  }
123
123
  };
124
124
  exports.fetchWithRetry = fetchWithRetry;
125
+ const fetchPatchWithRetry = async (url, clientId, clientSecret, instanceUrl, token, body, retries = 5, baseDelay = 500) => {
126
+ const doFetch = async (bearer) => {
127
+ return fetch(url, {
128
+ method: "PATCH",
129
+ headers: {
130
+ Authorization: `Bearer ${bearer}`,
131
+ Accept: "application/json",
132
+ "Content-Type": "application/json"
133
+ },
134
+ body: JSON.stringify(body)
135
+ });
136
+ };
137
+ console.log(`Patching ${url}`);
138
+ let currentToken = token;
139
+ let tokenRefreshed = false;
140
+ let remainingRetries = retries;
141
+ let delay = baseDelay;
142
+ while (true) {
143
+ let res = await doFetch(currentToken);
144
+ if (res.status === 401 && !tokenRefreshed) {
145
+ console.warn("Token expired — renewing token…");
146
+ currentToken = await (0, oauthTokenService_1.getOAuthToken)(clientId, clientSecret, instanceUrl);
147
+ tokenRefreshed = true;
148
+ continue;
149
+ }
150
+ const responseText = await res.text();
151
+ const isNoRouteToHost = res.status === 400 &&
152
+ responseText.includes("NoRouteToHostException");
153
+ const isRetryableStatus = res.status === 400 ||
154
+ res.status === 429 ||
155
+ res.status === 502 ||
156
+ res.status === 503 ||
157
+ res.status === 504;
158
+ if ((isRetryableStatus || isNoRouteToHost) &&
159
+ remainingRetries > 0) {
160
+ const retryAfter = res.headers.get("Retry-After");
161
+ let retryDelay = delay;
162
+ if (retryAfter) {
163
+ const retryAfterSeconds = Number(retryAfter);
164
+ if (!Number.isNaN(retryAfterSeconds)) {
165
+ retryDelay = retryAfterSeconds * 1000;
166
+ }
167
+ }
168
+ console.warn(`Retrying in ${retryDelay}ms... (${remainingRetries} retries left)`);
169
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
170
+ remainingRetries--;
171
+ delay *= 2;
172
+ continue;
173
+ }
174
+ if (!res.ok) {
175
+ throw new Error(`Request failed: ${res.status} ${res.statusText}\n${responseText}`);
176
+ }
177
+ let data;
178
+ try {
179
+ data = JSON.parse(responseText);
180
+ }
181
+ catch {
182
+ throw new Error(`Invalid JSON response from ${url}\n${responseText}`);
183
+ }
184
+ return {
185
+ data,
186
+ token: currentToken
187
+ };
188
+ }
189
+ };
190
+ exports.fetchPatchWithRetry = fetchPatchWithRetry;
191
+ const fetchPostWithRetry = async (url, clientId, clientSecret, instanceUrl, token, body, retries = 5, baseDelay = 500) => {
192
+ const doFetch = async (bearer) => {
193
+ return fetch(url, {
194
+ method: "POST",
195
+ headers: {
196
+ Authorization: `Bearer ${bearer}`,
197
+ Accept: "application/json",
198
+ "Content-Type": "application/json"
199
+ },
200
+ body: JSON.stringify(body)
201
+ });
202
+ };
203
+ console.log(`Posting ${url}`);
204
+ let currentToken = token;
205
+ let tokenRefreshed = false;
206
+ let remainingRetries = retries;
207
+ let delay = baseDelay;
208
+ while (true) {
209
+ let res = await doFetch(currentToken);
210
+ if (res.status === 401 && !tokenRefreshed) {
211
+ console.warn("Token expired — renewing token…");
212
+ currentToken = await (0, oauthTokenService_1.getOAuthToken)(clientId, clientSecret, instanceUrl);
213
+ tokenRefreshed = true;
214
+ continue;
215
+ }
216
+ const responseText = await res.text();
217
+ const isNoRouteToHost = res.status === 400 &&
218
+ responseText.includes("NoRouteToHostException");
219
+ const isRetryableStatus = res.status === 400 ||
220
+ res.status === 429 ||
221
+ res.status === 502 ||
222
+ res.status === 503 ||
223
+ res.status === 504;
224
+ if ((isRetryableStatus || isNoRouteToHost) &&
225
+ remainingRetries > 0) {
226
+ const retryAfter = res.headers.get("Retry-After");
227
+ let retryDelay = delay;
228
+ if (retryAfter) {
229
+ const retryAfterSeconds = Number(retryAfter);
230
+ if (!Number.isNaN(retryAfterSeconds)) {
231
+ retryDelay = retryAfterSeconds * 1000;
232
+ }
233
+ }
234
+ console.warn(`Retrying in ${retryDelay}ms... (${remainingRetries} retries left)`);
235
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
236
+ remainingRetries--;
237
+ delay *= 2;
238
+ continue;
239
+ }
240
+ if (!res.ok) {
241
+ throw new Error(`Request failed: ${res.status} ${res.statusText}\n${responseText}`);
242
+ }
243
+ let data;
244
+ try {
245
+ data = JSON.parse(responseText);
246
+ }
247
+ catch {
248
+ throw new Error(`Invalid JSON response from ${url}\n${responseText}`);
249
+ }
250
+ return {
251
+ data,
252
+ token: currentToken
253
+ };
254
+ }
255
+ };
256
+ exports.fetchPostWithRetry = fetchPostWithRetry;
125
257
  const fs_1 = __importDefault(require("fs"));
126
258
  const path_1 = __importDefault(require("path"));
127
259
  function saveCsv(rows, filePath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofsc-utility",
3
- "version": "1.0.47",
3
+ "version": "1.0.49",
4
4
  "description": "TypeScript helpers for Oracle Field Service Cloud (OFSC): events, resources, inventories, metadata and CSV/Excel utilities.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/readme.md CHANGED
@@ -8,6 +8,11 @@ This package exposes grouped API helpers for common OFSC operations, including:
8
8
  - export/download helpers
9
9
  - inventory and activity records
10
10
  - metadata file generation
11
+ - user and resource operations for standalone OFSC environments
12
+
13
+ > Note: User and resource-related methods are applicable exclusively to standalone OFSC environments and are not supported in Fusion OFSC.
14
+
15
+ This library is intended for OFSC integrations where the standard OFSC REST APIs are available. The user and resource-related methods are designed for standalone OFSC deployments and should not be relied on for Fusion OFSC environments, where the underlying APIs and behavior can differ.
11
16
 
12
17
  ### Built-in resilience for OFSC's server errors
13
18
 
@@ -172,6 +177,210 @@ await ofs.downloadAllInactiveUsersCSV(
172
177
  );
173
178
  ```
174
179
 
180
+ ### Resource APIs
181
+
182
+ The resource helpers let you export, paginate, inspect, and update OFSC resources.
183
+
184
+ #### `downloadAllResourcesCSV`
185
+
186
+ Exports every resource in the OFSC resource collection to a local `./resources.csv` file.
187
+
188
+ ```js
189
+ await ofs.downloadAllResourcesCSV(
190
+ process.env.CLIENT_ID,
191
+ process.env.CLIENT_SECRET,
192
+ process.env.INSTANCE_NAME,
193
+ );
194
+ ```
195
+
196
+ What it does:
197
+
198
+ - Calls the OFSC `/resources` endpoint in pages of 100 records.
199
+ - Aggregates all returned items across all pages.
200
+ - Builds a union of all field names from the API payloads.
201
+ - Excludes nested relationship fields such as `links`, `inventories`, `users`,
202
+ `workZones`, `workSkills`, and `workSchedules` from the header set.
203
+ - Writes the result to `./resources.csv` in the current working directory.
204
+ - Serializes arrays under the `keys` field as pipe-delimited strings and JSON-serializes object values for CSV compatibility.
205
+
206
+ Signature:
207
+
208
+ ```ts
209
+ downloadAllResourcesCSV(
210
+ clientId: string,
211
+ clientSecret: string,
212
+ instanceUrl: string,
213
+ ): Promise<void>
214
+ ```
215
+
216
+ #### `AllResources`
217
+
218
+ Fetches all resources across all pages and returns them as a single flattened array.
219
+
220
+ ```js
221
+ const resources = await ofs.AllResources(
222
+ process.env.CLIENT_ID,
223
+ process.env.CLIENT_SECRET,
224
+ process.env.INSTANCE_NAME,
225
+ );
226
+
227
+ console.log(`Found ${resources.length} resources`);
228
+ ```
229
+
230
+ This helper is useful when you need to iterate through every resource object in memory, for analytics, reporting, or bulk transformations.
231
+
232
+ Signature:
233
+
234
+ ```ts
235
+ AllResources(
236
+ clientId: string,
237
+ clientSecret: string,
238
+ instanceUrl: string,
239
+ initialToken?: string,
240
+ ): Promise<ResourceResponse[]>
241
+ ```
242
+
243
+ Notes:
244
+
245
+ - It paginates automatically until all results are fetched.
246
+ - It returns the flattened `items` collection from every page rather than the raw API wrapper object.
247
+ - The optional `initialToken` parameter can be supplied if you already have a valid bearer token available and want to reuse it.
248
+
249
+ #### `getworkSkillsOfResource`
250
+
251
+ Retrieves all work skills assigned to a specific resource.
252
+
253
+ ```js
254
+ const result = await ofs.getworkSkillsOfResource(
255
+ process.env.CLIENT_ID,
256
+ process.env.CLIENT_SECRET,
257
+ process.env.INSTANCE_NAME,
258
+ 12345,
259
+ );
260
+
261
+ console.log(result.data);
262
+ console.log(result.token);
263
+ ```
264
+
265
+
266
+ Signature:
267
+
268
+ ```ts
269
+ getworkSkillsOfResource(
270
+ clientId: string,
271
+ clientSecret: string,
272
+ instanceUrl: string,
273
+ resourceId: number,
274
+ token?: string,
275
+ ): Promise<{ token: string; data: any }>
276
+ ```
277
+
278
+ Return shape:
279
+
280
+ ```ts
281
+ {
282
+ token: string,
283
+ data: any
284
+ }
285
+ ```
286
+
287
+ The `data` value is the `items` array returned by OFSC for the resource's work skills.
288
+
289
+ #### `getResourcebyId`
290
+
291
+ Fetches a single resource by its ID.
292
+
293
+ ```js
294
+ const resource = await ofs.getResourcebyId(
295
+ "resource-123",
296
+ process.env.CLIENT_ID,
297
+ process.env.CLIENT_SECRET,
298
+ process.env.INSTANCE_NAME,
299
+ );
300
+
301
+ console.log(resource);
302
+ ```
303
+
304
+
305
+
306
+ Signature:
307
+
308
+ ```ts
309
+ getResourcebyId(
310
+ resourceId: string,
311
+ clientId: string,
312
+ clientSecret: string,
313
+ instanceUrl: string,
314
+ initialToken?: string,
315
+ ): Promise<ResourceResponse>
316
+ ```
317
+
318
+ The response is the raw OFSC resource payload returned by the API, so you can inspect its `items`, `totalResults`, and related metadata with the same structure returned by OFSC.
319
+
320
+ #### `updateResourcebyId`
321
+
322
+ Updates a resource record by ID using a PATCH request.
323
+
324
+ ```js
325
+ const payload = {
326
+ name: "Updated Resource Name",
327
+ status: "ACTIVE",
328
+ };
329
+
330
+ const response = await ofs.updateResourcebyId(
331
+ "resource-123",
332
+ process.env.CLIENT_ID,
333
+ process.env.CLIENT_SECRET,
334
+ process.env.INSTANCE_NAME,
335
+ "",
336
+ payload,
337
+ );
338
+
339
+ console.log(response);
340
+ ```
341
+
342
+ Signature:
343
+
344
+ ```ts
345
+ updateResourcebyId(
346
+ resourceId: string,
347
+ clientId: string,
348
+ clientSecret: string,
349
+ instanceUrl: string,
350
+ initialToken?: string,
351
+ payload: object,
352
+ ): Promise<ResourceResponse>
353
+ ```
354
+
355
+ Notes:
356
+
357
+ - The payload is sent as a PATCH body to the OFSC resource update endpoint.
358
+ - It uses the same retry-wrapper logic as the other OFSC API methods so transient gateway and 5xx failures are retried automatically.
359
+ - The returned value is the API response payload from OFSC.
360
+
361
+ #### Example: working with a resource and its work skills
362
+
363
+ ```js
364
+ const resourceId = "resource-123";
365
+
366
+ const resource = await ofs.getResourcebyId(
367
+ resourceId,
368
+ process.env.CLIENT_ID,
369
+ process.env.CLIENT_SECRET,
370
+ process.env.INSTANCE_NAME,
371
+ );
372
+
373
+ const workSkills = await ofs.getworkSkillsOfResource(
374
+ process.env.CLIENT_ID,
375
+ process.env.CLIENT_SECRET,
376
+ process.env.INSTANCE_NAME,
377
+ Number(resourceId),
378
+ );
379
+
380
+ console.log("Resource:", resource);
381
+ console.log("Work skills:", workSkills.data);
382
+ ```
383
+
175
384
  #### Download inactive users
176
385
 
177
386
  `downloadAllInactiveUsersCSV` downloads all users from the OFSC Users API, filters
@@ -333,8 +542,177 @@ node scripts/test-download-inactive-users-data.js
333
542
 
334
543
  `INACTIVITY_THRESHOLD_DAYS` is optional in the test script and defaults to `14`.
335
544
 
545
+ #### Get user by login
546
+
547
+ `getUserByLogin` fetches a single user record by login name and returns the raw OFSC response payload.
548
+
549
+ ```js
550
+ const user = await ofs.getUserByLogin(
551
+ "user@example.com",
552
+ process.env.CLIENT_ID,
553
+ process.env.CLIENT_SECRET,
554
+ process.env.INSTANCE_NAME,
555
+ );
556
+
557
+ console.log(user);
558
+ ```
559
+
560
+ **Function signature**
561
+
562
+ ```ts
563
+ getUserByLogin(
564
+ login: string,
565
+ clientId: string,
566
+ clientSecret: string,
567
+ instanceUrl: string,
568
+ initialToken?: string,
569
+ ): Promise<any>
570
+ ```
571
+
572
+ Notes:
573
+
574
+ - This method is intended for standalone OFSC environments.
575
+ - The response is the raw OFSC user payload returned by the API.
576
+ - `initialToken` is optional and can be reused if a bearer token is already available.
577
+
578
+ #### Update user by login
579
+
580
+ `updateUserbyLogin` updates a user record by login using a PATCH request.
581
+
582
+ ```js
583
+ const payload = {
584
+ firstName: "Updated",
585
+ lastName: "User",
586
+ status: "ACTIVE",
587
+ };
588
+
589
+ const response = await ofs.updateUserbyLogin(
590
+ "user@example.com",
591
+ process.env.CLIENT_ID,
592
+ process.env.CLIENT_SECRET,
593
+ process.env.INSTANCE_NAME,
594
+ "",
595
+ payload,
596
+ );
597
+
598
+ console.log(response);
599
+ ```
600
+
601
+ **Function signature**
602
+
603
+ ```ts
604
+ updateUserbyLogin(
605
+ login: string,
606
+ clientId: string,
607
+ clientSecret: string,
608
+ instanceUrl: string,
609
+ initialToken?: string,
610
+ payload: object,
611
+ ): Promise<ResourceResponse>
612
+ ```
613
+
614
+ Notes:
615
+
616
+ - The payload is sent as a PATCH body to the OFSC user update endpoint.
617
+ - It uses the same retry wrapper as the other OFSC API helpers.
618
+ - This method is also intended for standalone OFSC usage and may not behave the same in Fusion OFSC.
619
+
336
620
  ### Resource related methods
337
621
 
622
+ > Note: User and resource-related methods are applicable exclusively to standalone OFSC environments and are not supported in Fusion OFSC.
623
+
624
+ These methods are for standalone OFSC environments only. If you are connecting to Fusion OFSC, the user- and resource-based APIs may not behave the same way, and the request/response structure may not match the standalone endpoints.
625
+
626
+ #### Get all resources
627
+
628
+ `AllResources` retrieves all resources from the OFSC Resources API. Results are
629
+ fetched in pages of 100 records until every resource has been returned.
630
+
631
+ ```js
632
+ const resources = await ofs.AllResources(
633
+ process.env.CLIENT_ID,
634
+ process.env.CLIENT_SECRET,
635
+ process.env.INSTANCE_NAME,
636
+ );
637
+
638
+ console.log(`Loaded ${resources.length} resources`);
639
+ ```
640
+
641
+ **Function signature**
642
+
643
+ ```ts
644
+ AllResources(
645
+ clientId: string,
646
+ clientSecret: string,
647
+ instanceUrl: string,
648
+ initialToken?: string,
649
+ ): Promise<ResourceResponse[]>
650
+ ```
651
+
652
+ `initialToken` is optional. The helper refreshes the token as needed while
653
+ requesting subsequent pages.
654
+
655
+ #### Get a resource by ID
656
+
657
+ `getResourcebyId` fetches a single resource by its resource ID and returns the
658
+ OFSC response envelope.
659
+
660
+ ```js
661
+ const resource = await ofs.getResourcebyId(
662
+ "5457",
663
+ process.env.CLIENT_ID,
664
+ process.env.CLIENT_SECRET,
665
+ process.env.INSTANCE_NAME,
666
+ );
667
+
668
+ console.log(resource.items);
669
+ ```
670
+
671
+ **Function signature**
672
+
673
+ ```ts
674
+ getResourcebyId(
675
+ resourceId: string,
676
+ clientId: string,
677
+ clientSecret: string,
678
+ instanceUrl: string,
679
+ initialToken?: string,
680
+ ): Promise<ResourceResponse>
681
+ ```
682
+
683
+ The returned response contains `items`, `offset`, `limit`, and `totalResults`.
684
+ `initialToken` is optional.
685
+
686
+ #### Get resource work skills
687
+
688
+ `getworkSkillsOfResource` retrieves the work skills assigned to a resource.
689
+ The result includes the token returned by the request and the skills in `data`.
690
+
691
+ ```js
692
+ const workSkills = await ofs.getworkSkillsOfResource(
693
+ process.env.CLIENT_ID,
694
+ process.env.CLIENT_SECRET,
695
+ process.env.INSTANCE_NAME,
696
+ 5457,
697
+ );
698
+
699
+ console.log(workSkills.data);
700
+ ```
701
+
702
+ **Function signature**
703
+
704
+ ```ts
705
+ getworkSkillsOfResource(
706
+ clientId: string,
707
+ clientSecret: string,
708
+ instanceUrl: string,
709
+ resourceId: number,
710
+ token?: string,
711
+ ): Promise<{ token: string; data: any }>
712
+ ```
713
+
714
+ `token` is optional. `data` contains the work-skill items returned by OFSC.
715
+
338
716
  ```js
339
717
  await ofs.generateAllOnHandInventoryOfAllResourcesCSV(
340
718
  process.env.CLIENT_ID,