facility-core 2.0.0 → 2.2.0

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/package.json CHANGED
@@ -1,28 +1,34 @@
1
1
  {
2
2
  "name": "facility-core",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "Common code for the Facility API Framework.",
5
5
  "scripts": {
6
- "build": "tsc && tslint --exclude **/*.d.ts src/*.ts",
7
- "test": "npm run --silent build && mocha"
6
+ "build": "tsc && eslint src --ext .ts",
7
+ "test": "npm run --silent build && mocha",
8
+ "format": "prettier --write src/*.ts"
8
9
  },
9
10
  "repository": {
10
11
  "type": "git",
11
12
  "url": "https://github.com/FacilityApi/FacilityJavaScript.git"
12
13
  },
13
14
  "author": "Ed Ball",
14
- "license": "UNLICENSED",
15
+ "license": "MIT",
15
16
  "files": [
16
17
  "src"
17
18
  ],
18
19
  "main": "src/facilityCore.js",
19
20
  "types": "src/facilityCore.d.ts",
20
21
  "devDependencies": {
21
- "@types/chai": "^4.1.7",
22
- "@types/mocha": "^5.2.5",
23
- "chai": "^4.2.0",
24
- "mocha": "^5.2.0",
25
- "tslint": "^3.15.1",
26
- "typescript": "^2.0.9"
22
+ "@types/chai": "^4.2.18",
23
+ "@types/mocha": "^8.2.2",
24
+ "@typescript-eslint/eslint-plugin": "^4.26.1",
25
+ "@typescript-eslint/parser": "^4.26.1",
26
+ "chai": "^4.3.4",
27
+ "eslint": "^7.28.0",
28
+ "eslint-config-prettier": "^8.3.0",
29
+ "eslint-plugin-prettier": "^3.4.0",
30
+ "mocha": "^8.4.0",
31
+ "prettier": "^2.3.1",
32
+ "typescript": "~3.9.9"
27
33
  }
28
34
  }
@@ -15,7 +15,7 @@ export interface IServiceError {
15
15
  /** The error message. (For developers, not end users.) */
16
16
  message?: string;
17
17
  /** Advanced error details. */
18
- details?: any;
18
+ details?: Record<string, unknown>;
19
19
  /** The inner error. */
20
20
  innerError?: IServiceError;
21
21
  }
@@ -30,12 +30,12 @@ export interface IHttpClientOptions {
30
30
  export declare namespace HttpClientUtility {
31
31
  /** The fetch function. */
32
32
  interface IFetch {
33
- (uri: string, request: IFetchRequest): Promise<IFetchResponse>;
33
+ (uri: string, request: IFetchRequest, context?: unknown): Promise<IFetchResponse>;
34
34
  }
35
35
  /** The minimal fetch request. */
36
36
  interface IFetchRequest {
37
37
  method?: string;
38
- headers?: any;
38
+ headers?: Record<string, string>;
39
39
  body?: string;
40
40
  }
41
41
  /** The minimal fetch response. */
@@ -44,19 +44,19 @@ export declare namespace HttpClientUtility {
44
44
  headers: {
45
45
  get(name: string): string | null;
46
46
  };
47
- json(): Promise<any>;
47
+ json(): Promise<unknown>;
48
48
  }
49
49
  /** A fetch response with any fetched content. */
50
50
  interface IFetchedResponseWithContent {
51
51
  /** The fetch response. */
52
52
  response: IFetchResponse;
53
53
  /** The fetched JSON, if any. */
54
- json?: any;
54
+ json?: unknown;
55
55
  }
56
56
  /** Fetch JSON using the specified fetch, URI, and request. */
57
- function fetchResponse(fetch: IFetch, uri: string, request: IFetchRequest): Promise<IFetchedResponseWithContent>;
57
+ function fetchResponse(fetch: IFetch, uri: string, request: IFetchRequest, context?: unknown): Promise<IFetchedResponseWithContent>;
58
58
  /** Creates an error result for the specified response. */
59
- function createResponseError(status: number, json?: any): IServiceResultBase;
59
+ function createResponseError(status: number, json?: unknown): IServiceResultBase;
60
60
  /** Creates an error result for a required request field. */
61
61
  function createRequiredRequestFieldError(name: string): IServiceResultBase;
62
62
  }
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpClientUtility = void 0;
3
4
  /** Helpers for HTTP clients. */
5
+ // eslint-disable-next-line @typescript-eslint/no-namespace
4
6
  var HttpClientUtility;
5
7
  (function (HttpClientUtility) {
6
- var standardErrorCodes = {
8
+ const standardErrorCodes = {
7
9
  '304': 'NotModified',
8
10
  '400': 'InvalidRequest',
9
11
  '401': 'NotAuthenticated',
@@ -13,26 +15,28 @@ var HttpClientUtility;
13
15
  '413': 'RequestTooLarge',
14
16
  '429': 'TooManyRequests',
15
17
  '500': 'InternalError',
16
- '503': 'ServiceUnavailable'
18
+ '503': 'ServiceUnavailable',
17
19
  };
18
- var jsonContentType = 'application/json';
20
+ const jsonContentType = 'application/json';
19
21
  /** Fetch JSON using the specified fetch, URI, and request. */
20
- function fetchResponse(fetch, uri, request) {
21
- return fetch(uri, request)
22
- .then(function (response) {
22
+ function fetchResponse(fetch, uri, request, context) {
23
+ return fetch(uri, request, context).then((response) => {
23
24
  if (!response.headers || !response.status || typeof response.json !== 'function') {
24
25
  throw new TypeError('fetch must resolve Promise with { status, headers, json() }.');
25
26
  }
26
- var contentType = response.headers.get('content-type');
27
+ const contentType = response.headers.get('content-type');
27
28
  if (!contentType) {
28
29
  return Promise.resolve({ response: response, json: {} });
29
30
  }
30
31
  if (contentType.toLowerCase().substr(0, jsonContentType.length) === jsonContentType) {
31
- var jsonPromise = response.json();
32
+ const jsonPromise = response.json();
32
33
  if (!jsonPromise || typeof jsonPromise.then !== 'function') {
33
34
  throw new TypeError('json() of fetch response must return a Promise.');
34
35
  }
35
- return jsonPromise.then(function (json) { return ({ response: response, json: json }); });
36
+ return jsonPromise.then((json) => ({
37
+ response: response,
38
+ json: json,
39
+ }));
36
40
  }
37
41
  return Promise.resolve({ response: response });
38
42
  });
@@ -40,20 +44,32 @@ var HttpClientUtility;
40
44
  HttpClientUtility.fetchResponse = fetchResponse;
41
45
  /** Creates an error result for the specified response. */
42
46
  function createResponseError(status, json) {
43
- if (json && json.code) {
47
+ if (isServiceError(json)) {
44
48
  return { error: json };
45
49
  }
46
- var isClientError = status >= 400 && status <= 499;
47
- var isServerError = status >= 500 && status <= 599;
48
- var errorCode = standardErrorCodes[status] || (isClientError ? 'InvalidRequest' : 'InvalidResponse');
49
- var message = isServerError ? 'HTTP server error' : isClientError ? 'HTTP client error' : 'Unexpected HTTP status code';
50
- return { error: { code: errorCode, message: message + ": " + status } };
50
+ const isClientError = status >= 400 && status <= 499;
51
+ const isServerError = status >= 500 && status <= 599;
52
+ const errorCode = standardErrorCodes[status] || (isClientError ? 'InvalidRequest' : 'InvalidResponse');
53
+ const message = isServerError
54
+ ? 'HTTP server error'
55
+ : isClientError
56
+ ? 'HTTP client error'
57
+ : 'Unexpected HTTP status code';
58
+ return { error: { code: errorCode, message: `${message}: ${status}` } };
51
59
  }
52
60
  HttpClientUtility.createResponseError = createResponseError;
53
61
  /** Creates an error result for a required request field. */
54
62
  function createRequiredRequestFieldError(name) {
55
- return { error: { code: 'InvalidRequest', message: "The request field '" + name + "' is required." } };
63
+ return {
64
+ error: {
65
+ code: 'InvalidRequest',
66
+ message: `The request field '${name}' is required.`,
67
+ },
68
+ };
56
69
  }
57
70
  HttpClientUtility.createRequiredRequestFieldError = createRequiredRequestFieldError;
58
71
  })(HttpClientUtility = exports.HttpClientUtility || (exports.HttpClientUtility = {}));
72
+ function isServiceError(json) {
73
+ return typeof json === 'object' && json != null && typeof json.code === 'string';
74
+ }
59
75
  //# sourceMappingURL=facilityCore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"facilityCore.js","sourceRoot":"","sources":["facilityCore.ts"],"names":[],"mappings":";;AAgCA,gCAAgC;AAChC,IAAiB,iBAAiB,CAoFjC;AApFD,WAAiB,iBAAiB;IA+BjC,IAAM,kBAAkB,GAAgC;QACvD,KAAK,EAAE,aAAa;QACpB,KAAK,EAAE,gBAAgB;QACvB,KAAK,EAAE,kBAAkB;QACzB,KAAK,EAAE,eAAe;QACtB,KAAK,EAAE,UAAU;QACjB,KAAK,EAAE,UAAU;QACjB,KAAK,EAAE,iBAAiB;QACxB,KAAK,EAAE,iBAAiB;QACxB,KAAK,EAAE,eAAe;QACtB,KAAK,EAAE,oBAAoB;KAC3B,CAAC;IAEF,IAAM,eAAe,GAAG,kBAAkB,CAAC;IAE3C,8DAA8D;IAC9D,uBAA8B,KAAa,EAAE,GAAW,EAAE,OAAsB;QAC/E,OAAO,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC;aACxB,IAAI,CAAC,UAAA,QAAQ;YACb,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,UAAU,EAAE;gBACjF,MAAM,IAAI,SAAS,CAAC,8DAA8D,CAAC,CAAC;aACpF;YACD,IAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YACzD,IAAI,CAAC,WAAW,EAAE;gBACjB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;aACzD;YACD,IAAI,WAAW,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,KAAK,eAAe,EAAE;gBACpF,IAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACpC,IAAI,CAAC,WAAW,IAAI,OAAO,WAAW,CAAC,IAAI,KAAK,UAAU,EAAE;oBAC3D,MAAM,IAAI,SAAS,CAAC,iDAAiD,CAAC,CAAC;iBACvE;gBACD,OAAO,WAAW,CAAC,IAAI,CAAC,UAAA,IAAI,IAAI,OAAA,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAApC,CAAoC,CAAC,CAAC;aACtE;YACD,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC;IAnBe,+BAAa,gBAmB5B,CAAA;IAED,0DAA0D;IAC1D,6BAAoC,MAAc,EAAE,IAAU;QAC7D,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE;YACtB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;SACvB;QACD,IAAM,aAAa,GAAG,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC;QACrD,IAAM,aAAa,GAAG,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC;QACrD,IAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACvG,IAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,6BAA6B,CAAC;QAC1H,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAK,OAAO,UAAK,MAAQ,EAAE,EAAE,CAAC;IACzE,CAAC;IATe,qCAAmB,sBASlC,CAAA;IAED,4DAA4D;IAC5D,yCAAgD,IAAY;QAC3D,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,wBAAsB,IAAI,mBAAgB,EAAE,EAAE,CAAC;IACnG,CAAC;IAFe,iDAA+B,kCAE9C,CAAA;AACF,CAAC,EApFgB,iBAAiB,GAAjB,yBAAiB,KAAjB,yBAAiB,QAoFjC"}
1
+ {"version":3,"file":"facilityCore.js","sourceRoot":"","sources":["facilityCore.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ export interface IServiceError {
17
17
  /** The error message. (For developers, not end users.) */
18
18
  message?: string;
19
19
  /** Advanced error details. */
20
- details?: any;
20
+ details?: Record<string, unknown>;
21
21
  /** The inner error. */
22
22
  innerError?: IServiceError;
23
23
  }
@@ -31,17 +31,17 @@ export interface IHttpClientOptions {
31
31
  }
32
32
 
33
33
  /** Helpers for HTTP clients. */
34
+ // eslint-disable-next-line @typescript-eslint/no-namespace
34
35
  export namespace HttpClientUtility {
35
-
36
36
  /** The fetch function. */
37
37
  export interface IFetch {
38
- (uri: string, request: IFetchRequest): Promise<IFetchResponse>;
38
+ (uri: string, request: IFetchRequest, context?: unknown): Promise<IFetchResponse>;
39
39
  }
40
40
 
41
41
  /** The minimal fetch request. */
42
42
  export interface IFetchRequest {
43
43
  method?: string;
44
- headers?: any;
44
+ headers?: Record<string, string>;
45
45
  body?: string;
46
46
  }
47
47
 
@@ -51,7 +51,7 @@ export namespace HttpClientUtility {
51
51
  headers: {
52
52
  get(name: string): string | null;
53
53
  };
54
- json(): Promise<any>;
54
+ json(): Promise<unknown>;
55
55
  }
56
56
 
57
57
  /** A fetch response with any fetched content. */
@@ -59,7 +59,7 @@ export namespace HttpClientUtility {
59
59
  /** The fetch response. */
60
60
  response: IFetchResponse;
61
61
  /** The fetched JSON, if any. */
62
- json?: any;
62
+ json?: unknown;
63
63
  }
64
64
 
65
65
  const standardErrorCodes: { [index: number]: string } = {
@@ -72,47 +72,67 @@ export namespace HttpClientUtility {
72
72
  '413': 'RequestTooLarge',
73
73
  '429': 'TooManyRequests',
74
74
  '500': 'InternalError',
75
- '503': 'ServiceUnavailable'
75
+ '503': 'ServiceUnavailable',
76
76
  };
77
77
 
78
78
  const jsonContentType = 'application/json';
79
79
 
80
80
  /** Fetch JSON using the specified fetch, URI, and request. */
81
- export function fetchResponse(fetch: IFetch, uri: string, request: IFetchRequest): Promise<IFetchedResponseWithContent> {
82
- return fetch(uri, request)
83
- .then(response => {
84
- if (!response.headers || !response.status || typeof response.json !== 'function') {
85
- throw new TypeError('fetch must resolve Promise with { status, headers, json() }.');
86
- }
87
- const contentType = response.headers.get('content-type');
88
- if (!contentType) {
89
- return Promise.resolve({ response: response, json: {} });
90
- }
91
- if (contentType.toLowerCase().substr(0, jsonContentType.length) === jsonContentType) {
92
- const jsonPromise = response.json();
93
- if (!jsonPromise || typeof jsonPromise.then !== 'function') {
94
- throw new TypeError('json() of fetch response must return a Promise.');
95
- }
96
- return jsonPromise.then(json => ({ response: response, json: json }));
81
+ export function fetchResponse(
82
+ fetch: IFetch,
83
+ uri: string,
84
+ request: IFetchRequest,
85
+ context?: unknown
86
+ ): Promise<IFetchedResponseWithContent> {
87
+ return fetch(uri, request, context).then((response) => {
88
+ if (!response.headers || !response.status || typeof response.json !== 'function') {
89
+ throw new TypeError('fetch must resolve Promise with { status, headers, json() }.');
90
+ }
91
+ const contentType = response.headers.get('content-type');
92
+ if (!contentType) {
93
+ return Promise.resolve({ response: response, json: {} });
94
+ }
95
+ if (contentType.toLowerCase().substr(0, jsonContentType.length) === jsonContentType) {
96
+ const jsonPromise = response.json();
97
+ if (!jsonPromise || typeof jsonPromise.then !== 'function') {
98
+ throw new TypeError('json() of fetch response must return a Promise.');
97
99
  }
98
- return Promise.resolve({ response: response });
99
- });
100
+ return jsonPromise.then((json) => ({
101
+ response: response,
102
+ json: json,
103
+ }));
104
+ }
105
+ return Promise.resolve({ response: response });
106
+ });
100
107
  }
101
108
 
102
109
  /** Creates an error result for the specified response. */
103
- export function createResponseError(status: number, json?: any): IServiceResultBase {
104
- if (json && json.code) {
110
+ export function createResponseError(status: number, json?: unknown): IServiceResultBase {
111
+ if (isServiceError(json)) {
105
112
  return { error: json };
106
113
  }
107
114
  const isClientError = status >= 400 && status <= 499;
108
115
  const isServerError = status >= 500 && status <= 599;
109
116
  const errorCode = standardErrorCodes[status] || (isClientError ? 'InvalidRequest' : 'InvalidResponse');
110
- const message = isServerError ? 'HTTP server error' : isClientError ? 'HTTP client error' : 'Unexpected HTTP status code';
117
+ const message = isServerError
118
+ ? 'HTTP server error'
119
+ : isClientError
120
+ ? 'HTTP client error'
121
+ : 'Unexpected HTTP status code';
111
122
  return { error: { code: errorCode, message: `${message}: ${status}` } };
112
123
  }
113
124
 
114
125
  /** Creates an error result for a required request field. */
115
126
  export function createRequiredRequestFieldError(name: string): IServiceResultBase {
116
- return { error: { code: 'InvalidRequest', message: `The request field '${name}' is required.` } };
127
+ return {
128
+ error: {
129
+ code: 'InvalidRequest',
130
+ message: `The request field '${name}' is required.`,
131
+ },
132
+ };
117
133
  }
118
134
  }
135
+
136
+ function isServiceError(json: unknown): json is IServiceError {
137
+ return typeof json === 'object' && json != null && typeof (json as Record<string, unknown>).code === 'string';
138
+ }