@kwiz/node 1.0.14 → 1.0.17

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/src/auth/msal.ts CHANGED
@@ -1,44 +1,44 @@
1
- import { ConfidentialClientApplication } from "@azure/msal-node";
2
- import { AuthContextType, AuthenticationModes, ITenantInfo } from "@kwiz/common";
3
- //find tenant id? https://login.microsoftonline.com/kwizcom.onmicrosoft.com/.well-known/openid-configuration
4
- //https://stackoverflow.com/questions/54771270/msal-ad-token-not-valid-with-sharepoint-online-csom
5
-
6
- var apps: { [tenant: string]: ConfidentialClientApplication } = {};
7
-
8
- function GetApp(tenantInfo: ITenantInfo, auth: AuthContextType) {
9
- let key = `${tenantInfo.idOrName}|${auth.authenticationMode}`
10
- if (!apps[key]) {
11
- auth.authenticationMode === AuthenticationModes.clientSecret
12
- ? apps[key] = new ConfidentialClientApplication({
13
- auth: {
14
- clientId: auth.clientId,
15
- authority: tenantInfo.authorityUrl,
16
- clientSecret: auth.clientSecret
17
- },
18
-
19
- })
20
- : apps[key] = new ConfidentialClientApplication({
21
- auth: {
22
- clientId: auth.clientId,
23
- authority: tenantInfo.authorityUrl,
24
- clientCertificate: {
25
- thumbprint: auth.thumbprint,
26
- privateKey: auth.privateKey
27
- }
28
- },
29
-
30
- });
31
- }
32
- return apps[key];
33
- }
34
-
35
- /** client secret not supported by SharePoint, must use certificate */
36
- export async function GetMSALToken(tenantInfo: ITenantInfo, scope: string, auth: AuthContextType, clearCache?: boolean) {
37
- const app = GetApp(tenantInfo, auth);
38
- if (clearCache)
39
- app.clearCache();
40
- let token = await app.acquireTokenByClientCredential({
41
- scopes: [`${scope}/.default`]
42
- });
43
- return token.accessToken;
1
+ import { ConfidentialClientApplication } from "@azure/msal-node";
2
+ import { AuthContextType, AuthenticationModes, ITenantInfo } from "@kwiz/common";
3
+ //find tenant id? https://login.microsoftonline.com/kwizcom.onmicrosoft.com/.well-known/openid-configuration
4
+ //https://stackoverflow.com/questions/54771270/msal-ad-token-not-valid-with-sharepoint-online-csom
5
+
6
+ var apps: { [tenant: string]: ConfidentialClientApplication } = {};
7
+
8
+ function GetApp(tenantInfo: ITenantInfo, auth: AuthContextType) {
9
+ let key = `${tenantInfo.idOrName}|${auth.authenticationMode}`
10
+ if (!apps[key]) {
11
+ auth.authenticationMode === AuthenticationModes.clientSecret
12
+ ? apps[key] = new ConfidentialClientApplication({
13
+ auth: {
14
+ clientId: auth.clientId,
15
+ authority: tenantInfo.authorityUrl,
16
+ clientSecret: auth.clientSecret
17
+ },
18
+
19
+ })
20
+ : apps[key] = new ConfidentialClientApplication({
21
+ auth: {
22
+ clientId: auth.clientId,
23
+ authority: tenantInfo.authorityUrl,
24
+ clientCertificate: {
25
+ thumbprint: auth.thumbprint,
26
+ privateKey: auth.privateKey
27
+ }
28
+ },
29
+
30
+ });
31
+ }
32
+ return apps[key];
33
+ }
34
+
35
+ /** client secret not supported by SharePoint, must use certificate */
36
+ export async function GetMSALToken(tenantInfo: ITenantInfo, scope: string, auth: AuthContextType, clearCache?: boolean) {
37
+ const app = GetApp(tenantInfo, auth);
38
+ if (clearCache)
39
+ app.clearCache();
40
+ let token = await app.acquireTokenByClientCredential({
41
+ scopes: [`${scope}/.default`]
42
+ });
43
+ return token.accessToken;
44
44
  }
package/src/axios.ts CHANGED
@@ -1,32 +1,45 @@
1
- import { isNullOrEmptyString } from "@kwiz/common";
2
- import { AxiosRequestConfig } from "axios";
3
- import { Agent, globalAgent } from "https";
4
-
5
- type axiosConfigOptions = {
6
- contantType?: "application/json" | "application/json; odata=nometadata" | "application/xml";
7
- }
8
- export function getAxiosConfigBearer(token: string, options?: axiosConfigOptions) {
9
- return getAxiosConfig(`Bearer ${token}`, options);
10
- }
11
-
12
- export function getAxiosConfig(token?: string, options?: axiosConfigOptions) {
13
- //allow self sign ssl certificates
14
- globalAgent.options.rejectUnauthorized = false;
15
- const config: AxiosRequestConfig<any> = {
16
- httpAgent: new Agent({
17
- rejectUnauthorized: false
18
- }),
19
- headers: {}
20
- };
21
-
22
- if (!isNullOrEmptyString(token))
23
- config.headers!.Authorization = token;
24
-
25
- if (options) {
26
- if (!isNullOrEmptyString(options.contantType)) {
27
- config.headers!["Content-Type"] = options.contantType;
28
- config.headers!["Accept"] = options.contantType;
29
- }
30
- }
31
- return config;
1
+ import { isNullOrEmptyString } from "@kwiz/common";
2
+ import { AxiosError, AxiosRequestConfig } from "axios";
3
+ import { Agent, globalAgent } from "https";
4
+
5
+ type axiosConfigOptions = {
6
+ contantType?: "application/json" | "application/json; odata=nometadata" | "application/xml";
7
+ }
8
+ export function getAxiosConfigBearer(token: string, options?: axiosConfigOptions) {
9
+ return getAxiosConfig(`Bearer ${token}`, options);
10
+ }
11
+
12
+ export function getAxiosConfig(token?: string, options?: axiosConfigOptions) {
13
+ //allow self sign ssl certificates
14
+ globalAgent.options.rejectUnauthorized = false;
15
+ const config: AxiosRequestConfig<any> = {
16
+ httpAgent: new Agent({
17
+ rejectUnauthorized: false
18
+ }),
19
+ headers: {}
20
+ };
21
+
22
+ if (!isNullOrEmptyString(token))
23
+ config.headers!.Authorization = token;
24
+
25
+ if (options) {
26
+ if (!isNullOrEmptyString(options.contantType)) {
27
+ config.headers!["Content-Type"] = options.contantType;
28
+ config.headers!["Accept"] = options.contantType;
29
+ }
30
+ }
31
+ return config;
32
+ }
33
+
34
+ export function getAxiosErrorData(error: AxiosError) {
35
+ let code = error.code || "Unknown";
36
+ let errorMessage = error.message || "Unspecified error";
37
+ if (error && error.response && error.response.data && error.response.data["odata.error"]) {
38
+ let errorData: { code: string; message: { value: string; }; } = error.response.data["odata.error"];
39
+ if (errorData.message && errorData.message.value)
40
+ errorMessage = errorData.message.value;
41
+ if (errorData && errorData.code)
42
+ code = errorData.code;
43
+ }
44
+ return { code: code, message: errorMessage };
32
45
  }
@@ -3,3 +3,4 @@ export * from './auth/exports-index';
3
3
  export * from './graph/exports-index';
4
4
  export * from './storage/exports-index';
5
5
  export * from './axios';
6
+ export * from './get-with-cache';
@@ -0,0 +1,38 @@
1
+ import { IDictionary, isNullOrUndefined } from "@kwiz/common";
2
+
3
+ const $$cache: IDictionary<{ expires: Date; value: any }> = {};
4
+
5
+ export async function getWithCache<T>(worker: () => Promise<{ success: boolean; value: T }>, info: {
6
+ /** seconds */
7
+ successCacheDuration: number;
8
+ /** seconds */
9
+ failedCacheDuration?: number;
10
+ /** must be unique for your call! function name, and parameters */
11
+ cacheKey: string;
12
+ forceRefresh?: boolean;
13
+ }) {
14
+ const now = new Date();
15
+ //purge old values
16
+ Object.keys($$cache).forEach(key => {
17
+ if ($$cache[key].expires < now) delete $$cache[key];
18
+ });
19
+
20
+ let cached = info.forceRefresh ? null : $$cache[info.cacheKey];
21
+
22
+ if (isNullOrUndefined(cached)) {
23
+ const result = await worker();
24
+ if (result.success) {
25
+ $$cache[info.cacheKey] = {
26
+ expires: new Date(new Date().getTime() + info.successCacheDuration * 1000),
27
+ value: result.value
28
+ };
29
+ }
30
+ else if (info.failedCacheDuration > 0) {
31
+ $$cache[info.cacheKey] = {
32
+ expires: new Date(new Date().getTime() + info.failedCacheDuration * 1000),
33
+ value: result.value
34
+ };
35
+ }
36
+ }
37
+ return $$cache[info.cacheKey].value;
38
+ }
@@ -1,18 +1,18 @@
1
- import { AuthContextType, ITenantInfo, isNullOrUndefined } from "@kwiz/common";
2
- import { GetMSALToken } from "../auth/msal";
3
- import { getAxiosConfigBearer } from "../axios";
4
-
5
- /** "https://graph.microsoft.com" */
6
- export const graphScope = "https://graph.microsoft.com";
7
-
8
- var auth: AuthContextType = null;
9
- export function ConfigureGraphAuth(config?: AuthContextType) {
10
- auth = config;
11
- }
12
- export async function getAxiosConfigGraph(tenantInfo: ITenantInfo, clearCache?: boolean) {
13
- if (isNullOrUndefined(auth)) throw Error("Call ConfigureGraphAuth first");
14
-
15
- // secret or certificate supported
16
- let token = await GetMSALToken(tenantInfo, graphScope, auth, clearCache);
17
- return getAxiosConfigBearer(token);
1
+ import { AuthContextType, ITenantInfo, isNullOrUndefined } from "@kwiz/common";
2
+ import { GetMSALToken } from "../auth/msal";
3
+ import { getAxiosConfigBearer } from "../axios";
4
+
5
+ /** "https://graph.microsoft.com" */
6
+ export const graphScope = "https://graph.microsoft.com";
7
+
8
+ var auth: AuthContextType = null;
9
+ export function ConfigureGraphAuth(config?: AuthContextType) {
10
+ auth = config;
11
+ }
12
+ export async function getAxiosConfigGraph(tenantInfo: ITenantInfo, clearCache?: boolean) {
13
+ if (isNullOrUndefined(auth)) throw Error("Call ConfigureGraphAuth first");
14
+
15
+ // secret or certificate supported
16
+ let token = await GetMSALToken(tenantInfo, graphScope, auth, clearCache);
17
+ return getAxiosConfigBearer(token);
18
18
  }
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export * from "./exports-index";
1
+ export * from "./exports-index";
@@ -1,15 +1,15 @@
1
- import { isNullOrEmptyString } from "@kwiz/common";
2
- import axios from "axios";
3
-
4
- export async function IsAzuriteRunning() {
5
- let responseServer = "";
6
- try {
7
- //make a request for http://127.0.0.1:10000/ expect response headers "Server" to contain "Azurite"
8
- const result = await axios.get("http://127.0.0.1:10000/");
9
- responseServer = result.headers.server;
10
- } catch (e) {
11
- responseServer = e.response && e.response.headers && e.response.headers.server;
12
- }
13
-
14
- return isNullOrEmptyString(responseServer) ? false : responseServer.toLowerCase().indexOf("azurite") >= 0;
15
- }
1
+ import { isNullOrEmptyString } from "@kwiz/common";
2
+ import axios from "axios";
3
+
4
+ export async function IsAzuriteRunning() {
5
+ let responseServer = "";
6
+ try {
7
+ //make a request for http://127.0.0.1:10000/ expect response headers "Server" to contain "Azurite"
8
+ const result = await axios.get("http://127.0.0.1:10000/");
9
+ responseServer = result.headers.server;
10
+ } catch (e) {
11
+ responseServer = e.response && e.response.headers && e.response.headers.server;
12
+ }
13
+
14
+ return isNullOrEmptyString(responseServer) ? false : responseServer.toLowerCase().indexOf("azurite") >= 0;
15
+ }
@@ -1,87 +1,87 @@
1
- import { isNullOrEmptyArray, isNullOrEmptyString, isNullOrUndefined } from "@kwiz/common";
2
-
3
- export enum ODataOperators {
4
- equal = "eq",
5
- notEqual = "ne",
6
- greater = "gt",
7
- greaterOrEqual = "ge",
8
- less = "lt",
9
- lessOrEqual = "le",
10
- contains = "in",
11
- startswith = "startswith"
12
- }
13
- export enum ODataJoinOperators {
14
- and = "and",
15
- or = "or"
16
- }
17
-
18
- export interface IOdataFilter<DataType> {
19
- property: keyof DataType;
20
- operator: ODataOperators;
21
- value: string | Date | number | boolean;
22
- not?: boolean;
23
- }
24
- export interface IOdataFilterStatement<DataType> {
25
- filters: (IOdataFilter<DataType> | IOdataFilterStatement<DataType>)[];
26
- /** default: or */
27
- join?: ODataJoinOperators;
28
- not?: boolean;
29
- }
30
- function isIOdataFilter<DataType>(f: IOdataFilter<DataType> | IOdataFilterStatement<DataType>): f is IOdataFilter<DataType> {
31
- if (typeof (f as IOdataFilter<DataType>).property === "string")
32
- return true;
33
- return false;
34
- }
35
- function isIOdataFilterStatement<DataType>(f: IOdataFilter<DataType> | IOdataFilterStatement<DataType>): f is IOdataFilter<DataType> {
36
- if (typeof (f as IOdataFilterStatement<DataType>).filters === "object" && Array.isArray((f as IOdataFilterStatement<DataType>).filters))
37
- return true;
38
- return false;
39
- }
40
-
41
- enum TableStorageKnownColumns {
42
- partitionKey = "PartitionKey",
43
- rowKey = "RowKey"
44
- }
45
-
46
- function getPropNameForFilter(prop: string | number | symbol) {
47
- return TableStorageKnownColumns[prop] || prop as string;
48
- }
49
- function getOdataFilterStatement<DataType>(filter: IOdataFilter<DataType>) {
50
- let filterValue = isNullOrUndefined(filter.value)
51
- ? `null`
52
- : typeof filter.value === "string"
53
- ? `'${filter.value.replace(/'/g, "''")}'`
54
- : filter.value instanceof Date
55
- ? `'${filter.value.toISOString()}'`
56
- : `${filter.value}`;
57
-
58
- if (filter.operator === ODataOperators.startswith)
59
- return `${filter.not ? 'not ' : ''}${filter.operator}(${getPropNameForFilter(filter.property)}, ${filterValue})`;
60
- return `${filter.not ? 'not ' : ''}${getPropNameForFilter(filter.property)} ${filter.operator} ${filterValue}`;
61
- }
62
-
63
- export function getOdataFilter<DataType>(statement: IOdataFilterStatement<DataType>) {
64
- if (isNullOrUndefined(statement) || isNullOrEmptyArray(statement.filters)) return "";
65
- if (isNullOrEmptyString(statement.join)) statement.join = ODataJoinOperators.or;
66
-
67
- let filterStatements: string[] = [];
68
- statement.filters.forEach(filter => {
69
- if (isIOdataFilter(filter)) {
70
- filterStatements.push(getOdataFilterStatement<DataType>(filter));
71
- }
72
- else {
73
- let subStatement = getOdataFilter(filter);
74
- if (!isNullOrEmptyString(subStatement))
75
- filterStatements.push(subStatement);
76
- }
77
- });
78
- if (filterStatements.length === 0) return "";
79
-
80
- let result = "";
81
- if (filterStatements.length === 1) result = filterStatements[0];
82
- else if (filterStatements.length > 1) {
83
- result = `(${filterStatements.join(` ${statement.join} `)})`;
84
- }
85
-
86
- return `${statement.not ? '(not ' : ''}${result}${statement.not ? ')' : ''}`;
1
+ import { isNullOrEmptyArray, isNullOrEmptyString, isNullOrUndefined } from "@kwiz/common";
2
+
3
+ export enum ODataOperators {
4
+ equal = "eq",
5
+ notEqual = "ne",
6
+ greater = "gt",
7
+ greaterOrEqual = "ge",
8
+ less = "lt",
9
+ lessOrEqual = "le",
10
+ contains = "in",
11
+ startswith = "startswith"
12
+ }
13
+ export enum ODataJoinOperators {
14
+ and = "and",
15
+ or = "or"
16
+ }
17
+
18
+ export interface IOdataFilter<DataType> {
19
+ property: keyof DataType;
20
+ operator: ODataOperators;
21
+ value: string | Date | number | boolean;
22
+ not?: boolean;
23
+ }
24
+ export interface IOdataFilterStatement<DataType> {
25
+ filters: (IOdataFilter<DataType> | IOdataFilterStatement<DataType>)[];
26
+ /** default: or */
27
+ join?: ODataJoinOperators;
28
+ not?: boolean;
29
+ }
30
+ function isIOdataFilter<DataType>(f: IOdataFilter<DataType> | IOdataFilterStatement<DataType>): f is IOdataFilter<DataType> {
31
+ if (typeof (f as IOdataFilter<DataType>).property === "string")
32
+ return true;
33
+ return false;
34
+ }
35
+ function isIOdataFilterStatement<DataType>(f: IOdataFilter<DataType> | IOdataFilterStatement<DataType>): f is IOdataFilter<DataType> {
36
+ if (typeof (f as IOdataFilterStatement<DataType>).filters === "object" && Array.isArray((f as IOdataFilterStatement<DataType>).filters))
37
+ return true;
38
+ return false;
39
+ }
40
+
41
+ enum TableStorageKnownColumns {
42
+ partitionKey = "PartitionKey",
43
+ rowKey = "RowKey"
44
+ }
45
+
46
+ function getPropNameForFilter(prop: string | number | symbol) {
47
+ return TableStorageKnownColumns[prop] || prop as string;
48
+ }
49
+ function getOdataFilterStatement<DataType>(filter: IOdataFilter<DataType>) {
50
+ let filterValue = isNullOrUndefined(filter.value)
51
+ ? `null`
52
+ : typeof filter.value === "string"
53
+ ? `'${filter.value.replace(/'/g, "''")}'`
54
+ : filter.value instanceof Date
55
+ ? `'${filter.value.toISOString()}'`
56
+ : `${filter.value}`;
57
+
58
+ if (filter.operator === ODataOperators.startswith)
59
+ return `${filter.not ? 'not ' : ''}${filter.operator}(${getPropNameForFilter(filter.property)}, ${filterValue})`;
60
+ return `${filter.not ? 'not ' : ''}${getPropNameForFilter(filter.property)} ${filter.operator} ${filterValue}`;
61
+ }
62
+
63
+ export function getOdataFilter<DataType>(statement: IOdataFilterStatement<DataType>) {
64
+ if (isNullOrUndefined(statement) || isNullOrEmptyArray(statement.filters)) return "";
65
+ if (isNullOrEmptyString(statement.join)) statement.join = ODataJoinOperators.or;
66
+
67
+ let filterStatements: string[] = [];
68
+ statement.filters.forEach(filter => {
69
+ if (isIOdataFilter(filter)) {
70
+ filterStatements.push(getOdataFilterStatement<DataType>(filter));
71
+ }
72
+ else {
73
+ let subStatement = getOdataFilter(filter);
74
+ if (!isNullOrEmptyString(subStatement))
75
+ filterStatements.push(subStatement);
76
+ }
77
+ });
78
+ if (filterStatements.length === 0) return "";
79
+
80
+ let result = "";
81
+ if (filterStatements.length === 1) result = filterStatements[0];
82
+ else if (filterStatements.length > 1) {
83
+ result = `(${filterStatements.join(` ${statement.join} `)})`;
84
+ }
85
+
86
+ return `${statement.not ? '(not ' : ''}${result}${statement.not ? ')' : ''}`;
87
87
  }