@adobe-commerce/aio-toolkit 1.0.0 → 1.0.2

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/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import openwhisk, { Dict, Activation } from 'openwhisk';
2
+ import { Response } from 'node-fetch';
2
3
  import { Logger } from '@adobe/aio-sdk';
3
4
  import { Got, RequestError } from 'got';
4
5
 
@@ -11,13 +12,13 @@ declare enum HttpStatus {
11
12
  INTERNAL_ERROR = 500
12
13
  }
13
14
  declare enum HttpMethod {
14
- GET = "get",
15
- POST = "post",
16
- PUT = "put",
17
- DELETE = "delete",
18
- PATCH = "patch",
19
- HEAD = "head",
20
- OPTIONS = "options"
15
+ GET = "GET",
16
+ POST = "POST",
17
+ PUT = "PUT",
18
+ DELETE = "DELETE",
19
+ PATCH = "PATCH",
20
+ HEAD = "HEAD",
21
+ OPTIONS = "OPTIONS"
21
22
  }
22
23
 
23
24
  interface SuccessResponse {
@@ -120,9 +121,9 @@ declare class OpenwhiskAction {
120
121
  }
121
122
 
122
123
  interface FileRecord {
123
- id: string | number;
124
- created_at: string;
125
- updated_at: string;
124
+ id: string;
125
+ createdAt: string;
126
+ updatedAt: string;
126
127
  [key: string]: any;
127
128
  }
128
129
 
@@ -132,8 +133,9 @@ declare class FileRepository {
132
133
  constructor(filepath: string);
133
134
  list(): Promise<FileRecord[]>;
134
135
  load(id?: string): Promise<FileRecord>;
135
- save(payload?: Partial<FileRecord>): Promise<boolean>;
136
- delete(ids?: (string | number)[]): Promise<FileRecord[]>;
136
+ save(payload?: Partial<FileRecord>, id?: string | null): Promise<string | null>;
137
+ delete(ids?: string[]): Promise<FileRecord[]>;
138
+ private sanitizeFileId;
137
139
  private getFiles;
138
140
  }
139
141
 
@@ -146,7 +148,7 @@ interface BearerTokenInfo {
146
148
  }
147
149
 
148
150
  declare class BearerToken {
149
- static extract(params: {
151
+ static extract(headersOrParams: {
150
152
  [key: string]: any;
151
153
  }): BearerTokenInfo;
152
154
  static info(token: string | null): BearerTokenInfo;
@@ -159,10 +161,12 @@ interface Headers {
159
161
  }
160
162
 
161
163
  declare class RestClient {
162
- get(endpoint: string, headers?: Headers): Promise<any>;
163
- post(endpoint: string, headers?: Headers, payload?: any): Promise<any>;
164
- put(endpoint: string, headers?: Headers, payload?: any): Promise<any>;
165
- delete(endpoint: string, headers?: Headers): Promise<any>;
164
+ makeRequest(endpoint: string, method?: string, headers?: Headers, payload?: any): Promise<Response>;
165
+ parseResponse(response: Response): Promise<any>;
166
+ get(endpoint: string, headers?: Headers, parsed?: boolean): Promise<Response | any>;
167
+ post(endpoint: string, headers?: Headers, payload?: any, parsed?: boolean): Promise<Response | any>;
168
+ put(endpoint: string, headers?: Headers, payload?: any, parsed?: boolean): Promise<Response | any>;
169
+ delete(endpoint: string, headers?: Headers, parsed?: boolean): Promise<Response | any>;
166
170
  apiCall(endpoint: string, method?: string, headers?: Headers, payload?: any): Promise<any>;
167
171
  }
168
172
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import openwhisk, { Dict, Activation } from 'openwhisk';
2
+ import { Response } from 'node-fetch';
2
3
  import { Logger } from '@adobe/aio-sdk';
3
4
  import { Got, RequestError } from 'got';
4
5
 
@@ -11,13 +12,13 @@ declare enum HttpStatus {
11
12
  INTERNAL_ERROR = 500
12
13
  }
13
14
  declare enum HttpMethod {
14
- GET = "get",
15
- POST = "post",
16
- PUT = "put",
17
- DELETE = "delete",
18
- PATCH = "patch",
19
- HEAD = "head",
20
- OPTIONS = "options"
15
+ GET = "GET",
16
+ POST = "POST",
17
+ PUT = "PUT",
18
+ DELETE = "DELETE",
19
+ PATCH = "PATCH",
20
+ HEAD = "HEAD",
21
+ OPTIONS = "OPTIONS"
21
22
  }
22
23
 
23
24
  interface SuccessResponse {
@@ -120,9 +121,9 @@ declare class OpenwhiskAction {
120
121
  }
121
122
 
122
123
  interface FileRecord {
123
- id: string | number;
124
- created_at: string;
125
- updated_at: string;
124
+ id: string;
125
+ createdAt: string;
126
+ updatedAt: string;
126
127
  [key: string]: any;
127
128
  }
128
129
 
@@ -132,8 +133,9 @@ declare class FileRepository {
132
133
  constructor(filepath: string);
133
134
  list(): Promise<FileRecord[]>;
134
135
  load(id?: string): Promise<FileRecord>;
135
- save(payload?: Partial<FileRecord>): Promise<boolean>;
136
- delete(ids?: (string | number)[]): Promise<FileRecord[]>;
136
+ save(payload?: Partial<FileRecord>, id?: string | null): Promise<string | null>;
137
+ delete(ids?: string[]): Promise<FileRecord[]>;
138
+ private sanitizeFileId;
137
139
  private getFiles;
138
140
  }
139
141
 
@@ -146,7 +148,7 @@ interface BearerTokenInfo {
146
148
  }
147
149
 
148
150
  declare class BearerToken {
149
- static extract(params: {
151
+ static extract(headersOrParams: {
150
152
  [key: string]: any;
151
153
  }): BearerTokenInfo;
152
154
  static info(token: string | null): BearerTokenInfo;
@@ -159,10 +161,12 @@ interface Headers {
159
161
  }
160
162
 
161
163
  declare class RestClient {
162
- get(endpoint: string, headers?: Headers): Promise<any>;
163
- post(endpoint: string, headers?: Headers, payload?: any): Promise<any>;
164
- put(endpoint: string, headers?: Headers, payload?: any): Promise<any>;
165
- delete(endpoint: string, headers?: Headers): Promise<any>;
164
+ makeRequest(endpoint: string, method?: string, headers?: Headers, payload?: any): Promise<Response>;
165
+ parseResponse(response: Response): Promise<any>;
166
+ get(endpoint: string, headers?: Headers, parsed?: boolean): Promise<Response | any>;
167
+ post(endpoint: string, headers?: Headers, payload?: any, parsed?: boolean): Promise<Response | any>;
168
+ put(endpoint: string, headers?: Headers, payload?: any, parsed?: boolean): Promise<Response | any>;
169
+ delete(endpoint: string, headers?: Headers, parsed?: boolean): Promise<Response | any>;
166
170
  apiCall(endpoint: string, method?: string, headers?: Headers, payload?: any): Promise<any>;
167
171
  }
168
172
 
package/dist/index.js CHANGED
@@ -76,13 +76,13 @@ var HttpStatus = /* @__PURE__ */ ((HttpStatus2) => {
76
76
  return HttpStatus2;
77
77
  })(HttpStatus || {});
78
78
  var HttpMethod = /* @__PURE__ */ ((HttpMethod3) => {
79
- HttpMethod3["GET"] = "get";
80
- HttpMethod3["POST"] = "post";
81
- HttpMethod3["PUT"] = "put";
82
- HttpMethod3["DELETE"] = "delete";
83
- HttpMethod3["PATCH"] = "patch";
84
- HttpMethod3["HEAD"] = "head";
85
- HttpMethod3["OPTIONS"] = "options";
79
+ HttpMethod3["GET"] = "GET";
80
+ HttpMethod3["POST"] = "POST";
81
+ HttpMethod3["PUT"] = "PUT";
82
+ HttpMethod3["DELETE"] = "DELETE";
83
+ HttpMethod3["PATCH"] = "PATCH";
84
+ HttpMethod3["HEAD"] = "HEAD";
85
+ HttpMethod3["OPTIONS"] = "OPTIONS";
86
86
  return HttpMethod3;
87
87
  })(HttpMethod || {});
88
88
 
@@ -256,9 +256,9 @@ var _RuntimeAction = class _RuntimeAction {
256
256
  if (errorMessage) {
257
257
  return response_default.error(400 /* BAD_REQUEST */, errorMessage);
258
258
  }
259
- const requestMethod = params.__ow_method;
259
+ const requestMethod = params.__ow_method?.toUpperCase();
260
260
  if (httpMethods.length > 0 && !httpMethods.includes(requestMethod)) {
261
- const errorMessage2 = `Invalid HTTP method: ${requestMethod}. Allowed methods are: ${httpMethods.join(", ")}`;
261
+ const errorMessage2 = `Invalid HTTP method: ${params.__ow_method}. Allowed methods are: ${httpMethods.join(", ")}`;
262
262
  logger.error(errorMessage2);
263
263
  return response_default.error(405 /* METHOD_NOT_ALLOWED */, errorMessage2);
264
264
  }
@@ -319,7 +319,7 @@ var _GraphQlAction = class _GraphQlAction {
319
319
  }, name = "main", disableIntrospection = false) {
320
320
  return runtime_action_default.execute(
321
321
  `graphql-${name}`,
322
- ["get" /* GET */, "post" /* POST */],
322
+ ["GET" /* GET */, "POST" /* POST */],
323
323
  ["query"],
324
324
  [],
325
325
  async (params, ctx) => {
@@ -484,39 +484,44 @@ var _FileRepository = class _FileRepository {
484
484
  /**
485
485
  * Saves a file record to the repository
486
486
  * @param payload - The data to save
487
- * @returns Promise<boolean> True if save was successful, false otherwise
487
+ * @param id - Optional ID for the file (sanitized to alphanumeric + underscore, takes precedence over payload.id)
488
+ * @returns Promise<string | null> The filename on success, null on failure
488
489
  */
489
- async save(payload = {}) {
490
+ async save(payload = {}, id) {
490
491
  try {
491
492
  const filesLib = await this.getFiles();
492
- let requestFileId = (/* @__PURE__ */ new Date()).getTime();
493
- if ("id" in payload && payload.id !== void 0) {
494
- requestFileId = Number(payload.id);
493
+ let fileId;
494
+ if (id) {
495
+ fileId = this.sanitizeFileId(id);
496
+ } else if ("id" in payload && payload.id !== void 0) {
497
+ fileId = String(payload.id);
498
+ } else {
499
+ fileId = String((/* @__PURE__ */ new Date()).getTime());
495
500
  }
496
- const filepath = `${this.filepath}/${requestFileId}.json`;
501
+ const filepath = `${this.filepath}/${fileId}.json`;
497
502
  const existingFile = await filesLib.list(filepath);
498
503
  if (existingFile.length) {
499
504
  const buffer = await filesLib.read(filepath);
500
505
  const existingData = JSON.parse(buffer.toString());
501
506
  payload = {
502
507
  ...payload,
503
- updated_at: (/* @__PURE__ */ new Date()).toDateString()
508
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
504
509
  };
505
510
  payload = { ...existingData, ...payload };
506
511
  await filesLib.delete(filepath);
507
512
  } else {
508
513
  payload = {
509
514
  ...payload,
510
- id: requestFileId,
511
- created_at: (/* @__PURE__ */ new Date()).toDateString(),
512
- updated_at: (/* @__PURE__ */ new Date()).toDateString()
515
+ id: fileId,
516
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
517
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
513
518
  };
514
519
  }
515
520
  await filesLib.write(filepath, JSON.stringify(payload));
516
- return true;
521
+ return fileId;
517
522
  } catch (error) {
518
523
  console.error("Error saving file:", error);
519
- return false;
524
+ return null;
520
525
  }
521
526
  }
522
527
  /**
@@ -531,6 +536,21 @@ var _FileRepository = class _FileRepository {
531
536
  }
532
537
  return await this.list();
533
538
  }
539
+ /**
540
+ * Sanitizes the file ID to contain only alphanumeric characters and underscores
541
+ * @param id - The ID to sanitize
542
+ * @returns Sanitized ID with invalid characters replaced by underscores
543
+ */
544
+ sanitizeFileId(id) {
545
+ if (!id || typeof id !== "string") {
546
+ return String((/* @__PURE__ */ new Date()).getTime());
547
+ }
548
+ const sanitized = id.replace(/[^a-zA-Z0-9_]/g, "_");
549
+ if (!sanitized || /^_+$/.test(sanitized)) {
550
+ return String((/* @__PURE__ */ new Date()).getTime());
551
+ }
552
+ return sanitized;
553
+ }
534
554
  /**
535
555
  * Initializes and returns the Files library instance
536
556
  * @returns Promise<any> Initialized Files library instance
@@ -549,21 +569,31 @@ var file_repository_default = FileRepository;
549
569
  // src/integration/bearer-token/index.ts
550
570
  var _BearerToken = class _BearerToken {
551
571
  /**
552
- * Extracts the Bearer token from OpenWhisk action parameters and returns detailed token information.
553
- * Looks for the authorization header in __ow_headers and extracts the token value
554
- * after the "Bearer " prefix.
572
+ * Extracts the Bearer token from HTTP request headers and returns detailed token information.
573
+ * Supports both standard HTTP headers and OpenWhisk action parameter formats.
555
574
  *
556
- * @param params - OpenWhisk action input parameters containing headers
575
+ * @param headersOrParams - Either a standard headers object or OpenWhisk action parameters
557
576
  * @returns Detailed token information object
558
577
  *
559
578
  * @example
579
+ * // Standard HTTP headers approach
580
+ * const headers = {
581
+ * authorization: 'Bearer abc123token'
582
+ * };
583
+ * const tokenInfo = BearerToken.extract(headers);
584
+ *
585
+ * @example
586
+ * // OpenWhisk action parameters (backward compatibility)
560
587
  * const params = {
561
588
  * __ow_headers: {
562
589
  * authorization: 'Bearer abc123token'
563
590
  * }
564
591
  * };
565
592
  * const tokenInfo = BearerToken.extract(params);
566
- * // returns: {
593
+ *
594
+ * @example
595
+ * // Both return the same result:
596
+ * // {
567
597
  * // token: 'abc123token',
568
598
  * // tokenLength: 11,
569
599
  * // isValid: true,
@@ -571,26 +601,54 @@ var _BearerToken = class _BearerToken {
571
601
  * // timeUntilExpiry: 3600000
572
602
  * // }
573
603
  */
574
- static extract(params) {
604
+ static extract(headersOrParams) {
575
605
  let token = null;
576
- if (params.__ow_headers?.authorization?.startsWith("Bearer ")) {
577
- token = params.__ow_headers.authorization.substring("Bearer ".length);
606
+ if (headersOrParams.authorization?.startsWith("Bearer ")) {
607
+ token = headersOrParams.authorization.substring("Bearer ".length);
608
+ } else if (headersOrParams.__ow_headers?.authorization?.startsWith("Bearer ")) {
609
+ token = headersOrParams.__ow_headers.authorization.substring("Bearer ".length);
578
610
  }
579
611
  return _BearerToken.info(token);
580
612
  }
581
613
  /**
582
- * Gets detailed information about a Bearer token
583
- * @param token - The Bearer token string (or null)
584
- * @returns {BearerTokenInfo} Detailed token information including validity and expiry
614
+ * Analyzes a Bearer token and returns detailed information including validity and expiry.
615
+ * Supports both JWT tokens (with automatic expiry detection) and plain tokens (24h default expiry).
616
+ *
617
+ * @param token - The Bearer token string (or null). Can be JWT or plain token.
618
+ * @returns Detailed token information object
585
619
  *
586
620
  * @example
587
- * const tokenInfo = BearerToken.info('abc123token');
621
+ * // Plain token (gets 24h default expiry)
622
+ * const plainTokenInfo = BearerToken.info('abc123token');
588
623
  * // returns: {
589
624
  * // token: 'abc123token',
590
625
  * // tokenLength: 11,
591
626
  * // isValid: true,
592
- * // expiry: '2024-01-01T12:00:00.000Z',
593
- * // timeUntilExpiry: 3600000
627
+ * // expiry: '2024-01-02T12:00:00.000Z', // 24h from now
628
+ * // timeUntilExpiry: 86400000 // milliseconds until expiry
629
+ * // }
630
+ *
631
+ * @example
632
+ * // JWT token (automatic expiry detection from 'exp' or 'expires_in' claims)
633
+ * const jwtToken = 'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MDQ0Njc2MDB9.signature';
634
+ * const jwtTokenInfo = BearerToken.info(jwtToken);
635
+ * // returns: {
636
+ * // token: 'eyJhbGciOiJIUzI1NiJ9...',
637
+ * // tokenLength: 45,
638
+ * // isValid: true, // false if expired
639
+ * // expiry: '2024-01-05T12:00:00.000Z', // from JWT exp claim
640
+ * // timeUntilExpiry: 172800000 // actual time until expiry
641
+ * // }
642
+ *
643
+ * @example
644
+ * // Null or invalid token
645
+ * const nullTokenInfo = BearerToken.info(null);
646
+ * // returns: {
647
+ * // token: null,
648
+ * // tokenLength: 0,
649
+ * // isValid: false,
650
+ * // expiry: null,
651
+ * // timeUntilExpiry: null
594
652
  * // }
595
653
  */
596
654
  static info(token) {
@@ -656,14 +714,86 @@ var bearer_token_default = BearerToken;
656
714
  var import_node_fetch = __toESM(require("node-fetch"));
657
715
  var _RestClient = class _RestClient {
658
716
  /**
659
- * A generic method to make GET rest call
717
+ * A completely raw method to make HTTP requests
660
718
  *
661
719
  * @param endpoint
720
+ * @param method
662
721
  * @param headers
722
+ * @param payload
723
+ * @returns {Promise<Response>}
724
+ */
725
+ async makeRequest(endpoint, method = "GET", headers = {}, payload = null) {
726
+ let options = {
727
+ method,
728
+ headers
729
+ };
730
+ if (payload !== null) {
731
+ let body;
732
+ let contentType;
733
+ if (payload instanceof URLSearchParams) {
734
+ body = payload.toString();
735
+ contentType = headers["Content-Type"] || "application/x-www-form-urlencoded";
736
+ } else if (typeof FormData !== "undefined" && payload instanceof FormData) {
737
+ body = payload;
738
+ contentType = headers["Content-Type"];
739
+ } else if (typeof payload === "string") {
740
+ body = payload;
741
+ contentType = headers["Content-Type"] || "text/plain";
742
+ } else if (payload instanceof Buffer || payload instanceof ArrayBuffer || typeof Uint8Array !== "undefined" && payload instanceof Uint8Array) {
743
+ body = payload;
744
+ contentType = headers["Content-Type"] || "application/octet-stream";
745
+ } else {
746
+ body = JSON.stringify(payload);
747
+ contentType = headers["Content-Type"] || "application/json";
748
+ }
749
+ const requestHeaders = { ...headers };
750
+ if (contentType) {
751
+ requestHeaders["Content-Type"] = contentType;
752
+ }
753
+ options = {
754
+ ...options,
755
+ body,
756
+ headers: requestHeaders
757
+ };
758
+ }
759
+ return await (0, import_node_fetch.default)(endpoint, options);
760
+ }
761
+ /**
762
+ * A method to parse HTTP response
763
+ *
764
+ * @param response
663
765
  * @returns {Promise<any>}
664
766
  */
665
- async get(endpoint, headers = {}) {
666
- return await this.apiCall(endpoint, "GET", headers);
767
+ async parseResponse(response) {
768
+ if (!response.ok) {
769
+ throw new Error(`HTTP error! status: ${response.status}`);
770
+ }
771
+ if (response.status === 204 || response.headers?.get("content-length") === "0") {
772
+ return null;
773
+ }
774
+ if (typeof response.json === "function") {
775
+ const contentType = response.headers?.get("content-type");
776
+ if (!contentType || contentType.includes("application/json") || contentType.includes("application/hal+json")) {
777
+ return await response.json();
778
+ }
779
+ }
780
+ if (typeof response.text === "function") {
781
+ const text = await response.text();
782
+ return text;
783
+ }
784
+ return null;
785
+ }
786
+ /**
787
+ * A generic method to make GET rest call
788
+ *
789
+ * @param endpoint
790
+ * @param headers
791
+ * @param parsed
792
+ * @returns {Promise<Response | any>}
793
+ */
794
+ async get(endpoint, headers = {}, parsed = true) {
795
+ const response = await this.makeRequest(endpoint, "GET", headers);
796
+ return parsed ? await this.parseResponse(response) : response;
667
797
  }
668
798
  /**
669
799
  * A generic method to make POST rest call
@@ -671,10 +801,12 @@ var _RestClient = class _RestClient {
671
801
  * @param endpoint
672
802
  * @param headers
673
803
  * @param payload
674
- * @returns {Promise<any>}
804
+ * @param parsed
805
+ * @returns {Promise<Response | any>}
675
806
  */
676
- async post(endpoint, headers = {}, payload = null) {
677
- return await this.apiCall(endpoint, "POST", headers, payload);
807
+ async post(endpoint, headers = {}, payload = null, parsed = true) {
808
+ const response = await this.makeRequest(endpoint, "POST", headers, payload);
809
+ return parsed ? await this.parseResponse(response) : response;
678
810
  }
679
811
  /**
680
812
  * A generic method to make PUT rest call
@@ -682,20 +814,24 @@ var _RestClient = class _RestClient {
682
814
  * @param endpoint
683
815
  * @param headers
684
816
  * @param payload
685
- * @returns {Promise<any>}
817
+ * @param parsed
818
+ * @returns {Promise<Response | any>}
686
819
  */
687
- async put(endpoint, headers = {}, payload = null) {
688
- return await this.apiCall(endpoint, "PUT", headers, payload);
820
+ async put(endpoint, headers = {}, payload = null, parsed = true) {
821
+ const response = await this.makeRequest(endpoint, "PUT", headers, payload);
822
+ return parsed ? await this.parseResponse(response) : response;
689
823
  }
690
824
  /**
691
825
  * A generic method to make DELETE rest call
692
826
  *
693
827
  * @param endpoint
694
828
  * @param headers
695
- * @returns {Promise<any>}
829
+ * @param parsed
830
+ * @returns {Promise<Response | any>}
696
831
  */
697
- async delete(endpoint, headers = {}) {
698
- return await this.apiCall(endpoint, "DELETE", headers);
832
+ async delete(endpoint, headers = {}, parsed = true) {
833
+ const response = await this.makeRequest(endpoint, "DELETE", headers);
834
+ return parsed ? await this.parseResponse(response) : response;
699
835
  }
700
836
  /**
701
837
  * A generic method to make rest call
@@ -705,6 +841,7 @@ var _RestClient = class _RestClient {
705
841
  * @param headers
706
842
  * @param payload
707
843
  * @returns {Promise<any>}
844
+ * @deprecated Use makeRequest() and parseResponse() methods instead
708
845
  */
709
846
  async apiCall(endpoint, method = "POST", headers = {}, payload = null) {
710
847
  let options = {