@arcblock/jwt 1.16.16 → 1.17.1
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/lib/index.d.ts +67 -16
- package/lib/index.js +173 -184
- package/package.json +24 -10
package/lib/index.d.ts
CHANGED
|
@@ -1,16 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { BytesType } from '@ocap/util';
|
|
2
|
+
export declare type JwtBody = {
|
|
3
|
+
iss?: string;
|
|
4
|
+
iat?: string;
|
|
5
|
+
nbf?: string;
|
|
6
|
+
exp?: string;
|
|
7
|
+
version?: string;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
};
|
|
10
|
+
export declare type JwtHeader = {
|
|
11
|
+
alg: string;
|
|
12
|
+
type: 'JWT';
|
|
13
|
+
};
|
|
14
|
+
export declare type JwtToken = {
|
|
15
|
+
header: JwtHeader;
|
|
16
|
+
body: JwtBody;
|
|
17
|
+
signature: string;
|
|
18
|
+
};
|
|
19
|
+
export declare type JwtVerifyOptions = Partial<{
|
|
20
|
+
tolerance: number;
|
|
21
|
+
enforceTimestamp: boolean;
|
|
22
|
+
signerKey: string;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
*
|
|
27
|
+
* @param {string} signer - address string
|
|
28
|
+
* @param {string} sk - hex encoded secret key
|
|
29
|
+
* @param {*} [payload={}] - data to be included before signing
|
|
30
|
+
* @param {boolean} [doSign=true] - do we need to sign the payload or just return the content to be signed
|
|
31
|
+
* @param {string} [version='1.0.0']
|
|
32
|
+
* @return {*} {string} - hex encoded signature
|
|
33
|
+
*/
|
|
34
|
+
export declare function sign(signer: string, sk: string, payload?: {}, doSign?: boolean, version?: string): string;
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
*
|
|
38
|
+
* @param {string} token - jwt string
|
|
39
|
+
* @param {boolean} [payloadOnly=true]
|
|
40
|
+
* @return {*} {{
|
|
41
|
+
* header: any;
|
|
42
|
+
* body: any;
|
|
43
|
+
* signature: string;
|
|
44
|
+
* }}
|
|
45
|
+
*/
|
|
46
|
+
export declare function decode(token: string, payloadOnly?: boolean): JwtToken;
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
*
|
|
50
|
+
* @param {string} token - the jwt token
|
|
51
|
+
* @param {string} signerPk - signer public key
|
|
52
|
+
* @param {{
|
|
53
|
+
* tolerance: number; - number of seconds to tolerant expire
|
|
54
|
+
* enforceTimestamp: boolean; - whether should be verify timestamps?
|
|
55
|
+
* signerKey: string; - which field should be used to pick the signer
|
|
56
|
+
* }} [{
|
|
57
|
+
* tolerance,
|
|
58
|
+
* enforceTimestamp,
|
|
59
|
+
* signerKey,
|
|
60
|
+
* }={
|
|
61
|
+
* tolerance: 5,
|
|
62
|
+
* enforceTimestamp: true,
|
|
63
|
+
* signerKey: 'iss',
|
|
64
|
+
* }]
|
|
65
|
+
* @return {*} {boolean}
|
|
66
|
+
*/
|
|
67
|
+
export declare function verify(token: string, signerPk: BytesType, options?: JwtVerifyOptions): boolean;
|
package/lib/index.js
CHANGED
|
@@ -1,206 +1,195 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.verify = exports.decode = exports.sign = void 0;
|
|
7
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
8
|
+
const json_stable_stringify_1 = __importDefault(require("json-stable-stringify"));
|
|
9
|
+
const semver_1 = __importDefault(require("semver"));
|
|
10
|
+
const util_1 = require("@ocap/util");
|
|
11
|
+
const did_1 = require("@arcblock/did");
|
|
12
|
+
const mcrypto_1 = require("@ocap/mcrypto");
|
|
13
|
+
const debug_1 = __importDefault(require("debug"));
|
|
14
|
+
const debug = (0, debug_1.default)('@arcblock/jwt');
|
|
12
15
|
// we start hashing before signing after 1.1
|
|
13
16
|
const JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN = '1.1.0';
|
|
14
|
-
|
|
15
17
|
// since ios requires a fixed length of input to sign, we use sha3 here before sign
|
|
16
|
-
const hasher =
|
|
17
|
-
|
|
18
|
+
const hasher = mcrypto_1.Hasher.SHA3.hash256;
|
|
18
19
|
/**
|
|
19
|
-
* Generate and sign a jwt token
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
* @static
|
|
21
|
+
*
|
|
23
22
|
* @param {string} signer - address string
|
|
24
23
|
* @param {string} sk - hex encoded secret key
|
|
25
|
-
* @param {
|
|
24
|
+
* @param {*} [payload={}] - data to be included before signing
|
|
26
25
|
* @param {boolean} [doSign=true] - do we need to sign the payload or just return the content to be signed
|
|
27
|
-
* @
|
|
26
|
+
* @param {string} [version='1.0.0']
|
|
27
|
+
* @return {*} {string} - hex encoded signature
|
|
28
28
|
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
version,
|
|
62
|
-
...(payload || {}),
|
|
63
|
-
};
|
|
64
|
-
// remove empty keys
|
|
65
|
-
body = Object.keys(body)
|
|
66
|
-
.filter((x) => {
|
|
67
|
-
if (typeof body[x] === 'undefined' || body[x] == null || body[x] === '') {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return true;
|
|
29
|
+
function sign(signer, sk, payload = {}, doSign = true, version = '1.0.0') {
|
|
30
|
+
if ((0, did_1.isValid)(signer) === false) {
|
|
31
|
+
throw new Error('Cannot do sign with invalid signer');
|
|
32
|
+
}
|
|
33
|
+
const type = (0, did_1.toTypeInfo)(signer);
|
|
34
|
+
const headers = {
|
|
35
|
+
[mcrypto_1.types.KeyType.SECP256K1]: {
|
|
36
|
+
alg: 'ES256K',
|
|
37
|
+
type: 'JWT',
|
|
38
|
+
},
|
|
39
|
+
[mcrypto_1.types.KeyType.ED25519]: {
|
|
40
|
+
alg: 'Ed25519',
|
|
41
|
+
type: 'JWT',
|
|
42
|
+
},
|
|
43
|
+
[mcrypto_1.types.KeyType.ETHEREUM]: {
|
|
44
|
+
alg: 'Ethereum',
|
|
45
|
+
type: 'JWT',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
// make header
|
|
49
|
+
const header = headers[type.pk];
|
|
50
|
+
const headerB64 = (0, util_1.toBase64)((0, json_stable_stringify_1.default)(header));
|
|
51
|
+
// make body
|
|
52
|
+
const now = Math.floor(Date.now() / 1000);
|
|
53
|
+
let body = Object.assign({ iss: (0, did_1.toDid)(signer), iat: String(now), nbf: String(now), exp: String(now + 5 * 60), version }, (payload || {}));
|
|
54
|
+
// remove empty keys
|
|
55
|
+
body = Object.keys(body)
|
|
56
|
+
.filter((x) => {
|
|
57
|
+
if (typeof body[x] === 'undefined' || body[x] == null || body[x] === '') {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
72
61
|
})
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
.reduce((acc, x) => {
|
|
63
|
+
acc[x] = body[x];
|
|
64
|
+
return acc;
|
|
76
65
|
}, {});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return [headerB64, bodyB64, sigB64].join('.');
|
|
95
|
-
};
|
|
96
|
-
|
|
66
|
+
const bodyB64 = (0, util_1.toBase64)((0, json_stable_stringify_1.default)(body));
|
|
67
|
+
debug('sign.body', body);
|
|
68
|
+
// istanbul ignore if
|
|
69
|
+
if (!doSign) {
|
|
70
|
+
return `${headerB64}.${bodyB64}`;
|
|
71
|
+
}
|
|
72
|
+
// @ts-ignore make signature
|
|
73
|
+
const msgHex = (0, util_1.toHex)(`${headerB64}.${bodyB64}`);
|
|
74
|
+
const msgHash = semver_1.default.gte(semver_1.default.coerce(version).version, JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN)
|
|
75
|
+
? hasher(msgHex)
|
|
76
|
+
: msgHex;
|
|
77
|
+
const sigHex = (0, mcrypto_1.getSigner)(type.pk).sign(msgHash, sk);
|
|
78
|
+
const sigB64 = (0, util_1.toBase64)(sigHex);
|
|
79
|
+
return [headerB64, bodyB64, sigB64].join('.');
|
|
80
|
+
}
|
|
81
|
+
exports.sign = sign;
|
|
97
82
|
/**
|
|
98
|
-
* Decode info from jwt token
|
|
99
83
|
*
|
|
100
|
-
*
|
|
101
|
-
* @static
|
|
84
|
+
*
|
|
102
85
|
* @param {string} token - jwt string
|
|
103
|
-
* @param {boolean} [payloadOnly=
|
|
104
|
-
* @
|
|
86
|
+
* @param {boolean} [payloadOnly=true]
|
|
87
|
+
* @return {*} {{
|
|
88
|
+
* header: any;
|
|
89
|
+
* body: any;
|
|
90
|
+
* signature: string;
|
|
91
|
+
* }}
|
|
105
92
|
*/
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
93
|
+
function decode(token, payloadOnly = true) {
|
|
94
|
+
const [headerB64, bodyB64, sigB64] = token.split('.');
|
|
95
|
+
const header = JSON.parse((0, util_1.fromBase64)(headerB64).toString());
|
|
96
|
+
const body = JSON.parse((0, util_1.fromBase64)(bodyB64).toString());
|
|
97
|
+
const sig = Buffer.from((0, util_1.fromBase64)(sigB64)).toString('hex');
|
|
98
|
+
if (payloadOnly) {
|
|
99
|
+
return body;
|
|
100
|
+
}
|
|
101
|
+
return { header, body, signature: `0x${(0, did_1.toStrictHex)(sig)}` };
|
|
102
|
+
}
|
|
103
|
+
exports.decode = decode;
|
|
117
104
|
/**
|
|
118
|
-
* Verify a jwt token signed with signerPk and signerDid
|
|
119
105
|
*
|
|
120
|
-
*
|
|
121
|
-
* @
|
|
122
|
-
* @param {string} token - the jwt token
|
|
106
|
+
*
|
|
107
|
+
* @param {string} token - the jwt token
|
|
123
108
|
* @param {string} signerPk - signer public key
|
|
124
|
-
* @param {
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
109
|
+
* @param {{
|
|
110
|
+
* tolerance: number; - number of seconds to tolerant expire
|
|
111
|
+
* enforceTimestamp: boolean; - whether should be verify timestamps?
|
|
112
|
+
* signerKey: string; - which field should be used to pick the signer
|
|
113
|
+
* }} [{
|
|
114
|
+
* tolerance,
|
|
115
|
+
* enforceTimestamp,
|
|
116
|
+
* signerKey,
|
|
117
|
+
* }={
|
|
118
|
+
* tolerance: 5,
|
|
119
|
+
* enforceTimestamp: true,
|
|
120
|
+
* signerKey: 'iss',
|
|
121
|
+
* }]
|
|
122
|
+
* @return {*} {boolean}
|
|
129
123
|
*/
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
124
|
+
function verify(token, signerPk, options) {
|
|
125
|
+
const { tolerance, enforceTimestamp, signerKey } = Object.assign({
|
|
126
|
+
tolerance: 5,
|
|
127
|
+
enforceTimestamp: true,
|
|
128
|
+
signerKey: 'iss',
|
|
129
|
+
}, options);
|
|
130
|
+
try {
|
|
131
|
+
const [headerB64, bodyB64] = token.split('.');
|
|
132
|
+
const { header, body, signature } = decode(token, false);
|
|
133
|
+
if (!signature) {
|
|
134
|
+
debug('verify.error.emptySig');
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
if (!header.alg) {
|
|
138
|
+
debug('verify.error.emptyAlg');
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const signerDid = body[signerKey];
|
|
142
|
+
if (!signerDid) {
|
|
143
|
+
debug('verify.error.emptySignerDid');
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if ((0, did_1.isFromPublicKey)(signerDid, signerPk) === false) {
|
|
147
|
+
debug('verify.error.signerDidAndPkNotMatch');
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
if (enforceTimestamp) {
|
|
151
|
+
const now = Math.ceil(Date.now() / 1000);
|
|
152
|
+
const exp = Number(body.exp) || 0;
|
|
153
|
+
const iat = Number(body.iat) || 0;
|
|
154
|
+
const nbf = Number(body.nbf) || 0;
|
|
155
|
+
debug('verify.enforceTimestamp', { now, exp, iat, nbf });
|
|
156
|
+
if (exp && exp + tolerance < now) {
|
|
157
|
+
debug('verify.error.expired');
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
if (iat && iat > now && iat - now > tolerance) {
|
|
161
|
+
debug('verify.error.issuedAt');
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (nbf && nbf > now && nbf - now > tolerance) {
|
|
165
|
+
debug('verify.error.notBefore');
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const signers = {
|
|
170
|
+
secp256k1: (0, mcrypto_1.getSigner)(mcrypto_1.types.KeyType.SECP256K1),
|
|
171
|
+
es256k: (0, mcrypto_1.getSigner)(mcrypto_1.types.KeyType.SECP256K1),
|
|
172
|
+
ed25519: (0, mcrypto_1.getSigner)(mcrypto_1.types.KeyType.ED25519),
|
|
173
|
+
ethereum: (0, mcrypto_1.getSigner)(mcrypto_1.types.KeyType.ETHEREUM),
|
|
174
|
+
};
|
|
175
|
+
const alg = header.alg.toLowerCase();
|
|
176
|
+
if (signers[alg]) {
|
|
177
|
+
// @ts-ignore
|
|
178
|
+
const msgHex = (0, util_1.toHex)(`${headerB64}.${bodyB64}`);
|
|
179
|
+
// If we are using v1.1 protocol, the message should be hashed before verify
|
|
180
|
+
const version = body.version && semver_1.default.coerce(body.version) ? semver_1.default.coerce(body.version).version : '';
|
|
181
|
+
if (version && version === JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN) {
|
|
182
|
+
return signers[alg].verify(hasher(msgHex), signature, signerPk);
|
|
183
|
+
}
|
|
184
|
+
return signers[alg].verify(msgHex, signature, signerPk);
|
|
185
|
+
}
|
|
186
|
+
debug('verify.error.crypto');
|
|
166
187
|
return false;
|
|
167
|
-
}
|
|
168
|
-
if (nbf && nbf > now && nbf - now > tolerance) {
|
|
169
|
-
debug('verify.error.notBefore');
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
188
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
ed25519: getSigner(types.KeyType.ED25519),
|
|
178
|
-
ethereum: getSigner(types.KeyType.ETHEREUM),
|
|
179
|
-
};
|
|
180
|
-
const alg = header.alg.toLowerCase();
|
|
181
|
-
if (signers[alg]) {
|
|
182
|
-
const msgHex = toHex(`${headerB64}.${bodyB64}`);
|
|
183
|
-
|
|
184
|
-
// If we are using v1.1 protocol, the message should be hashed before verify
|
|
185
|
-
const version = body.version && semver.coerce(body.version) ? semver.coerce(body.version).version : '';
|
|
186
|
-
if (version && version === JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN) {
|
|
187
|
-
return signers[alg].verify(hasher(msgHex), signature, signerPk);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return signers[alg].verify(msgHex, signature, signerPk);
|
|
189
|
+
catch (err) {
|
|
190
|
+
debug('verify.error.exception');
|
|
191
|
+
debug(err);
|
|
192
|
+
return false;
|
|
191
193
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return false;
|
|
195
|
-
} catch (err) {
|
|
196
|
-
debug('verify.error.exception');
|
|
197
|
-
debug(err);
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
module.exports = {
|
|
203
|
-
sign,
|
|
204
|
-
verify,
|
|
205
|
-
decode,
|
|
206
|
-
};
|
|
194
|
+
}
|
|
195
|
+
exports.verify = verify;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcblock/jwt",
|
|
3
3
|
"description": "JSON Web Token variant for arcblock DID solutions",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.17.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "wangshijun",
|
|
7
7
|
"email": "shijun@arcblock.io",
|
|
@@ -18,15 +18,24 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@arcblock/did": "1.
|
|
22
|
-
"@ocap/mcrypto": "1.
|
|
23
|
-
"@ocap/util": "1.
|
|
21
|
+
"@arcblock/did": "1.17.1",
|
|
22
|
+
"@ocap/mcrypto": "1.17.1",
|
|
23
|
+
"@ocap/util": "1.17.1",
|
|
24
24
|
"debug": "^4.3.3",
|
|
25
25
|
"json-stable-stringify": "^1.0.1",
|
|
26
26
|
"semver": "^7.3.4"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"
|
|
29
|
+
"@arcblock/eslint-config-ts": "0.2.2",
|
|
30
|
+
"@types/jest": "^27.5.1",
|
|
31
|
+
"@types/json-stable-stringify": "^1.0.34",
|
|
32
|
+
"@types/node": "^17.0.33",
|
|
33
|
+
"@types/semver": "^7.3.9",
|
|
34
|
+
"eslint": "^8.17.0",
|
|
35
|
+
"jest": "^27.3.1",
|
|
36
|
+
"ts-jest": "^28.0.0",
|
|
37
|
+
"tslib": "^2.4.0",
|
|
38
|
+
"typescript": "^4.6.4"
|
|
30
39
|
},
|
|
31
40
|
"homepage": "https://github.com/ArcBlock/asset-chain/tree/master/did/jwt",
|
|
32
41
|
"keywords": [
|
|
@@ -36,7 +45,8 @@
|
|
|
36
45
|
"nodejs"
|
|
37
46
|
],
|
|
38
47
|
"license": "Apache-2.0",
|
|
39
|
-
"main": "
|
|
48
|
+
"main": "lib/index.js",
|
|
49
|
+
"typings": "lib/index.d.ts",
|
|
40
50
|
"files": [
|
|
41
51
|
"lib"
|
|
42
52
|
],
|
|
@@ -45,10 +55,14 @@
|
|
|
45
55
|
"url": "https://github.com/ArcBlock/asset-chain/tree/master/did/jwt"
|
|
46
56
|
},
|
|
47
57
|
"scripts": {
|
|
48
|
-
"lint": "eslint
|
|
49
|
-
"lint:fix": "eslint --fix
|
|
58
|
+
"lint": "eslint src tests",
|
|
59
|
+
"lint:fix": "eslint src tests --fix",
|
|
50
60
|
"test": "jest --forceExit --detectOpenHandles",
|
|
51
|
-
"coverage": "yarn test -- --coverage"
|
|
61
|
+
"coverage": "yarn test -- --coverage",
|
|
62
|
+
"clean": "rm -fr lib",
|
|
63
|
+
"prebuild": "npm run clean",
|
|
64
|
+
"build:watch": "npm run build -- -w",
|
|
65
|
+
"build": "tsc"
|
|
52
66
|
},
|
|
53
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "ca2ac264d9d6358680d5be99fcdd4685d0c999fc"
|
|
54
68
|
}
|