@usertour/helpers 0.0.8 → 0.0.9
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.cjs +8 -297
- package/dist/index.d.cts +0 -3
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -8
- package/dist/server.cjs +331 -0
- package/dist/server.d.cts +4 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +11 -0
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -37,8 +37,6 @@ var src_exports = {};
|
|
|
37
37
|
__export(src_exports, {
|
|
38
38
|
AbortController: () => AbortController,
|
|
39
39
|
ArrayProto: () => ArrayProto,
|
|
40
|
-
JWTLicenseSigner: () => JWTLicenseSigner,
|
|
41
|
-
JWTLicenseValidator: () => JWTLicenseValidator,
|
|
42
40
|
PRIORITIES: () => PRIORITIES,
|
|
43
41
|
XMLHttpRequest: () => XMLHttpRequest,
|
|
44
42
|
absoluteUrl: () => absoluteUrl,
|
|
@@ -473,8 +471,8 @@ var parseUrl = (url) => {
|
|
|
473
471
|
if (!urlPatterns) {
|
|
474
472
|
return null;
|
|
475
473
|
}
|
|
476
|
-
const [, , scheme = "", domain = "",
|
|
477
|
-
return { scheme, domain, path
|
|
474
|
+
const [, , scheme = "", domain = "", path = "", , query = "", fragment = ""] = urlPatterns;
|
|
475
|
+
return { scheme, domain, path, query, fragment };
|
|
478
476
|
};
|
|
479
477
|
var replaceWildcard = (input, s1, s2) => {
|
|
480
478
|
const withSpecialWords = replaceSpecialWords(input);
|
|
@@ -496,11 +494,11 @@ var parsePattern = (pattern) => {
|
|
|
496
494
|
console.error("Invalid URL pattern:", pattern);
|
|
497
495
|
return null;
|
|
498
496
|
}
|
|
499
|
-
const { scheme, domain, path
|
|
497
|
+
const { scheme, domain, path, query, fragment } = _pattern;
|
|
500
498
|
const _scheme = scheme ? replaceSpecialWords(scheme) : "[a-z\\d]+";
|
|
501
499
|
const _domain = domain ? replaceWildcard(domain, "[^/]", ".") : "[^/]*";
|
|
502
500
|
const _fragment = fragment ? replaceWildcard(fragment, ".", "/") : "(#.*)?";
|
|
503
|
-
const _path =
|
|
501
|
+
const _path = path ? replaceWildcard(path, "[^?#]", "/") : "/[^?#]*";
|
|
504
502
|
let _query = "(\\?[^#]*)?";
|
|
505
503
|
if (query) {
|
|
506
504
|
new URLSearchParams(query).forEach((value, key) => {
|
|
@@ -1063,8 +1061,8 @@ function formatDate(input) {
|
|
|
1063
1061
|
year: "numeric"
|
|
1064
1062
|
});
|
|
1065
1063
|
}
|
|
1066
|
-
function absoluteUrl(
|
|
1067
|
-
return `${
|
|
1064
|
+
function absoluteUrl(path) {
|
|
1065
|
+
return `${path}`;
|
|
1068
1066
|
}
|
|
1069
1067
|
var uuidV4 = () => {
|
|
1070
1068
|
return (0, import_uuid.v4)();
|
|
@@ -1112,291 +1110,6 @@ var getRandomColor = () => {
|
|
|
1112
1110
|
return colors[Math.floor(Math.random() * colors.length)];
|
|
1113
1111
|
};
|
|
1114
1112
|
|
|
1115
|
-
// src/jwt-license-signer.ts
|
|
1116
|
-
var fs = __toESM(require("fs"), 1);
|
|
1117
|
-
var path = __toESM(require("path"), 1);
|
|
1118
|
-
var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
|
|
1119
|
-
var JWTLicenseSigner = class {
|
|
1120
|
-
constructor(options) {
|
|
1121
|
-
__publicField(this, "privateKey");
|
|
1122
|
-
__publicField(this, "issuer");
|
|
1123
|
-
__publicField(this, "algorithm");
|
|
1124
|
-
this.privateKey = this.loadPrivateKey(options.privateKeyPath);
|
|
1125
|
-
this.issuer = options.issuer || "https://www.usertour.io";
|
|
1126
|
-
this.algorithm = options.algorithm || "RS256";
|
|
1127
|
-
}
|
|
1128
|
-
/**
|
|
1129
|
-
* Load RSA private key from file
|
|
1130
|
-
*/
|
|
1131
|
-
loadPrivateKey(keyPath) {
|
|
1132
|
-
try {
|
|
1133
|
-
const fullPath = path.resolve(keyPath);
|
|
1134
|
-
return fs.readFileSync(fullPath, "utf8");
|
|
1135
|
-
} catch (error) {
|
|
1136
|
-
throw new Error(`Failed to load private key from ${keyPath}: ${error}`);
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
/**
|
|
1140
|
-
* Generate a JWT license token
|
|
1141
|
-
*/
|
|
1142
|
-
generateLicense(options) {
|
|
1143
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
1144
|
-
const expiresAt = now + options.expiresInDays * 24 * 60 * 60;
|
|
1145
|
-
const payload = {
|
|
1146
|
-
plan: options.plan,
|
|
1147
|
-
sub: options.subject,
|
|
1148
|
-
projectId: options.projectId,
|
|
1149
|
-
iat: now,
|
|
1150
|
-
exp: expiresAt,
|
|
1151
|
-
issuer: options.issuer || this.issuer,
|
|
1152
|
-
features: options.features
|
|
1153
|
-
};
|
|
1154
|
-
try {
|
|
1155
|
-
return import_jsonwebtoken.default.sign(payload, this.privateKey, {
|
|
1156
|
-
algorithm: this.algorithm,
|
|
1157
|
-
issuer: this.issuer
|
|
1158
|
-
});
|
|
1159
|
-
} catch (error) {
|
|
1160
|
-
throw new Error(`Failed to generate JWT license: ${error}`);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
/**
|
|
1164
|
-
* Generate a license and return both token and payload info
|
|
1165
|
-
*/
|
|
1166
|
-
generateLicenseWithInfo(options) {
|
|
1167
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
1168
|
-
const expiresAt = now + options.expiresInDays * 24 * 60 * 60;
|
|
1169
|
-
const payload = {
|
|
1170
|
-
plan: options.plan,
|
|
1171
|
-
sub: options.subject,
|
|
1172
|
-
projectId: options.projectId,
|
|
1173
|
-
iat: now,
|
|
1174
|
-
exp: expiresAt,
|
|
1175
|
-
issuer: options.issuer || this.issuer,
|
|
1176
|
-
features: options.features
|
|
1177
|
-
};
|
|
1178
|
-
const token = import_jsonwebtoken.default.sign(payload, this.privateKey, {
|
|
1179
|
-
algorithm: this.algorithm,
|
|
1180
|
-
issuer: this.issuer
|
|
1181
|
-
});
|
|
1182
|
-
return {
|
|
1183
|
-
token,
|
|
1184
|
-
payload,
|
|
1185
|
-
expiresAt: new Date(expiresAt * 1e3)
|
|
1186
|
-
};
|
|
1187
|
-
}
|
|
1188
|
-
/**
|
|
1189
|
-
* Decode a JWT token without verification (for debugging)
|
|
1190
|
-
*/
|
|
1191
|
-
decodeToken(token) {
|
|
1192
|
-
try {
|
|
1193
|
-
return import_jsonwebtoken.default.decode(token);
|
|
1194
|
-
} catch (error) {
|
|
1195
|
-
console.error("Failed to decode JWT token:", error);
|
|
1196
|
-
return null;
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
/**
|
|
1200
|
-
* Get token information without verification
|
|
1201
|
-
*/
|
|
1202
|
-
getTokenInfo(token) {
|
|
1203
|
-
try {
|
|
1204
|
-
const decoded = import_jsonwebtoken.default.decode(token, { complete: true });
|
|
1205
|
-
if (!decoded || typeof decoded === "string") {
|
|
1206
|
-
return null;
|
|
1207
|
-
}
|
|
1208
|
-
return {
|
|
1209
|
-
header: decoded.header,
|
|
1210
|
-
payload: decoded.payload,
|
|
1211
|
-
signature: decoded.signature
|
|
1212
|
-
};
|
|
1213
|
-
} catch (error) {
|
|
1214
|
-
console.error("Failed to get token info:", error);
|
|
1215
|
-
return null;
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
};
|
|
1219
|
-
|
|
1220
|
-
// src/jwt-license-validator.ts
|
|
1221
|
-
var import_jsonwebtoken2 = __toESM(require("jsonwebtoken"), 1);
|
|
1222
|
-
var JWTLicenseValidator = {
|
|
1223
|
-
/**
|
|
1224
|
-
* Validate a JWT license
|
|
1225
|
-
* @param license - JWT license string
|
|
1226
|
-
* @param publicKey - RSA public key in PEM format
|
|
1227
|
-
* @param options - Validation options
|
|
1228
|
-
* @returns Validation result
|
|
1229
|
-
*/
|
|
1230
|
-
validateLicense(license, publicKey, options = {}) {
|
|
1231
|
-
try {
|
|
1232
|
-
const { checkExpiration = true, currentTime = /* @__PURE__ */ new Date() } = options;
|
|
1233
|
-
const decoded = import_jsonwebtoken2.default.verify(license, publicKey, {
|
|
1234
|
-
algorithms: ["RS256"],
|
|
1235
|
-
ignoreExpiration: !checkExpiration
|
|
1236
|
-
});
|
|
1237
|
-
const fieldValidation = this.validateRequiredFields(decoded);
|
|
1238
|
-
if (!fieldValidation.isValid) {
|
|
1239
|
-
return fieldValidation;
|
|
1240
|
-
}
|
|
1241
|
-
if (checkExpiration) {
|
|
1242
|
-
const expirationValidation = this.checkExpiration(decoded, currentTime);
|
|
1243
|
-
if (!expirationValidation.isValid) {
|
|
1244
|
-
return expirationValidation;
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
const hasFeature = (feature) => {
|
|
1248
|
-
return decoded.features.includes("*") || decoded.features.includes(feature);
|
|
1249
|
-
};
|
|
1250
|
-
return {
|
|
1251
|
-
isValid: true,
|
|
1252
|
-
payload: decoded,
|
|
1253
|
-
isExpired: false,
|
|
1254
|
-
hasFeature
|
|
1255
|
-
};
|
|
1256
|
-
} catch (error) {
|
|
1257
|
-
if (error instanceof import_jsonwebtoken2.default.JsonWebTokenError) {
|
|
1258
|
-
return {
|
|
1259
|
-
isValid: false,
|
|
1260
|
-
error: `JWT validation failed: ${error.message}`
|
|
1261
|
-
};
|
|
1262
|
-
}
|
|
1263
|
-
if (error instanceof import_jsonwebtoken2.default.TokenExpiredError) {
|
|
1264
|
-
return {
|
|
1265
|
-
isValid: false,
|
|
1266
|
-
error: `License expired: ${error.message}`,
|
|
1267
|
-
isExpired: true
|
|
1268
|
-
};
|
|
1269
|
-
}
|
|
1270
|
-
return {
|
|
1271
|
-
isValid: false,
|
|
1272
|
-
error: `License validation failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
},
|
|
1276
|
-
/**
|
|
1277
|
-
* Validate that all required fields are present in license payload
|
|
1278
|
-
* @param payload - License payload to validate
|
|
1279
|
-
* @returns Validation result
|
|
1280
|
-
*/
|
|
1281
|
-
validateRequiredFields(payload) {
|
|
1282
|
-
const requiredFields = ["plan", "sub", "projectId", "iat", "exp", "issuer", "features"];
|
|
1283
|
-
for (const field of requiredFields) {
|
|
1284
|
-
if (!(field in payload)) {
|
|
1285
|
-
return {
|
|
1286
|
-
isValid: false,
|
|
1287
|
-
error: `Missing required field: ${field}`
|
|
1288
|
-
};
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
if (typeof payload.plan !== "string" || !payload.plan.trim()) {
|
|
1292
|
-
return {
|
|
1293
|
-
isValid: false,
|
|
1294
|
-
error: "Invalid plan: must be a non-empty string"
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1297
|
-
if (typeof payload.sub !== "string" || !payload.sub.trim()) {
|
|
1298
|
-
return {
|
|
1299
|
-
isValid: false,
|
|
1300
|
-
error: "Invalid sub: must be a non-empty string"
|
|
1301
|
-
};
|
|
1302
|
-
}
|
|
1303
|
-
if (typeof payload.projectId !== "string" || !payload.projectId.trim()) {
|
|
1304
|
-
return {
|
|
1305
|
-
isValid: false,
|
|
1306
|
-
error: "Invalid projectId: must be a non-empty string"
|
|
1307
|
-
};
|
|
1308
|
-
}
|
|
1309
|
-
if (typeof payload.issuer !== "string" || !payload.issuer.trim()) {
|
|
1310
|
-
return {
|
|
1311
|
-
isValid: false,
|
|
1312
|
-
error: "Invalid issuer: must be a non-empty string"
|
|
1313
|
-
};
|
|
1314
|
-
}
|
|
1315
|
-
if (!Array.isArray(payload.features)) {
|
|
1316
|
-
return {
|
|
1317
|
-
isValid: false,
|
|
1318
|
-
error: "Invalid features: must be an array"
|
|
1319
|
-
};
|
|
1320
|
-
}
|
|
1321
|
-
if (typeof payload.iat !== "number" || payload.iat <= 0) {
|
|
1322
|
-
return {
|
|
1323
|
-
isValid: false,
|
|
1324
|
-
error: "Invalid iat: must be a positive number"
|
|
1325
|
-
};
|
|
1326
|
-
}
|
|
1327
|
-
if (typeof payload.exp !== "number" || payload.exp <= 0) {
|
|
1328
|
-
return {
|
|
1329
|
-
isValid: false,
|
|
1330
|
-
error: "Invalid exp: must be a positive number"
|
|
1331
|
-
};
|
|
1332
|
-
}
|
|
1333
|
-
if (payload.iat >= payload.exp) {
|
|
1334
|
-
return {
|
|
1335
|
-
isValid: false,
|
|
1336
|
-
error: "Invalid timestamps: iat must be before exp"
|
|
1337
|
-
};
|
|
1338
|
-
}
|
|
1339
|
-
return { isValid: true };
|
|
1340
|
-
},
|
|
1341
|
-
/**
|
|
1342
|
-
* Check if license has expired
|
|
1343
|
-
* @param payload - License payload
|
|
1344
|
-
* @param currentTime - Current time to check against (defaults to now)
|
|
1345
|
-
* @returns Validation result
|
|
1346
|
-
*/
|
|
1347
|
-
checkExpiration(payload, currentTime = /* @__PURE__ */ new Date()) {
|
|
1348
|
-
const now = Math.floor(currentTime.getTime() / 1e3);
|
|
1349
|
-
const expiresAt = payload.exp;
|
|
1350
|
-
if (now > expiresAt) {
|
|
1351
|
-
return {
|
|
1352
|
-
isValid: false,
|
|
1353
|
-
error: `License expired on ${new Date(expiresAt * 1e3).toISOString()}`,
|
|
1354
|
-
isExpired: true
|
|
1355
|
-
};
|
|
1356
|
-
}
|
|
1357
|
-
return { isValid: true, isExpired: false };
|
|
1358
|
-
},
|
|
1359
|
-
/**
|
|
1360
|
-
* Check if license has a specific feature
|
|
1361
|
-
* @param payload - License payload
|
|
1362
|
-
* @param feature - Feature to check
|
|
1363
|
-
* @returns Whether the feature is available
|
|
1364
|
-
*/
|
|
1365
|
-
hasFeature(payload, feature) {
|
|
1366
|
-
return payload.features.includes("*") || payload.features.includes(feature);
|
|
1367
|
-
},
|
|
1368
|
-
/**
|
|
1369
|
-
* Get license expiration status
|
|
1370
|
-
* @param payload - License payload
|
|
1371
|
-
* @param currentTime - Current time to check against (defaults to now)
|
|
1372
|
-
* @returns Expiration information
|
|
1373
|
-
*/
|
|
1374
|
-
getExpirationInfo(payload, currentTime = /* @__PURE__ */ new Date()) {
|
|
1375
|
-
const now = Math.floor(currentTime.getTime() / 1e3);
|
|
1376
|
-
const expiresAt = payload.exp;
|
|
1377
|
-
const isExpired = now > expiresAt;
|
|
1378
|
-
const daysUntilExpiration = Math.ceil((expiresAt - now) / (24 * 60 * 60));
|
|
1379
|
-
return {
|
|
1380
|
-
isExpired,
|
|
1381
|
-
expiresAt: new Date(expiresAt * 1e3),
|
|
1382
|
-
daysUntilExpiration: isExpired ? 0 : daysUntilExpiration
|
|
1383
|
-
};
|
|
1384
|
-
},
|
|
1385
|
-
/**
|
|
1386
|
-
* Decode JWT license without verification (for debugging)
|
|
1387
|
-
* @param license - JWT license string
|
|
1388
|
-
* @returns Decoded payload or null if invalid
|
|
1389
|
-
*/
|
|
1390
|
-
decodeLicense(license) {
|
|
1391
|
-
try {
|
|
1392
|
-
const decoded = import_jsonwebtoken2.default.decode(license);
|
|
1393
|
-
return decoded;
|
|
1394
|
-
} catch {
|
|
1395
|
-
return null;
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
};
|
|
1399
|
-
|
|
1400
1113
|
// src/conditions.ts
|
|
1401
1114
|
var import_dom = require("@floating-ui/dom");
|
|
1402
1115
|
|
|
@@ -2253,9 +1966,9 @@ var wait = (seconds) => {
|
|
|
2253
1966
|
if (seconds === 0) {
|
|
2254
1967
|
return Promise.resolve();
|
|
2255
1968
|
}
|
|
2256
|
-
return new Promise((
|
|
1969
|
+
return new Promise((resolve, reject) => {
|
|
2257
1970
|
try {
|
|
2258
|
-
setTimeout(
|
|
1971
|
+
setTimeout(resolve, seconds * 1e3);
|
|
2259
1972
|
} catch (error) {
|
|
2260
1973
|
reject(error);
|
|
2261
1974
|
}
|
|
@@ -2265,8 +1978,6 @@ var wait = (seconds) => {
|
|
|
2265
1978
|
0 && (module.exports = {
|
|
2266
1979
|
AbortController,
|
|
2267
1980
|
ArrayProto,
|
|
2268
|
-
JWTLicenseSigner,
|
|
2269
|
-
JWTLicenseValidator,
|
|
2270
1981
|
PRIORITIES,
|
|
2271
1982
|
XMLHttpRequest,
|
|
2272
1983
|
absoluteUrl,
|
package/dist/index.d.cts
CHANGED
|
@@ -11,8 +11,6 @@ export { isPublishedAtLeastOneEnvironment, isPublishedInAllEnvironments } from '
|
|
|
11
11
|
export { deepClone } from './utils.cjs';
|
|
12
12
|
export { generateAutoStateColors, hexToHSLString, hexToRGBStr } from './color.cjs';
|
|
13
13
|
export { absoluteUrl, cn, cuid, evalCode, formatDate, getRandomColor, hexToRgb, isDark, uuidV4 } from './helper.cjs';
|
|
14
|
-
export { GenerateLicenseOptions, JWTLicenseSigner, JWTLicenseSignerOptions } from './jwt-license-signer.cjs';
|
|
15
|
-
export { JWTLicenseValidator } from './jwt-license-validator.cjs';
|
|
16
14
|
export { PRIORITIES, activedContentCondition, activedContentRulesConditions, activedRulesConditions, checklistIsDimissed, checklistIsSeen, filterAutoStartContent, findLatestEvent, flowIsDismissed, flowIsSeen, isActive, isActiveContent, isHasActivedContents, isSameContents, isValidContent, isVisible, parseUrlParams, wait } from './conditions.cjs';
|
|
17
15
|
export { Options, Target, TargetResult, XData, XNode, XResult, finder, finderV2, finderX, parserV2, parserX } from './finderx.cjs';
|
|
18
16
|
export { default as isEqual } from 'fast-deep-equal';
|
|
@@ -20,4 +18,3 @@ import '@usertour/types';
|
|
|
20
18
|
import './storage.cjs';
|
|
21
19
|
import '@usertour/types/';
|
|
22
20
|
import 'clsx';
|
|
23
|
-
import 'jsonwebtoken';
|
package/dist/index.d.ts
CHANGED
|
@@ -11,8 +11,6 @@ export { isPublishedAtLeastOneEnvironment, isPublishedInAllEnvironments } from '
|
|
|
11
11
|
export { deepClone } from './utils.js';
|
|
12
12
|
export { generateAutoStateColors, hexToHSLString, hexToRGBStr } from './color.js';
|
|
13
13
|
export { absoluteUrl, cn, cuid, evalCode, formatDate, getRandomColor, hexToRgb, isDark, uuidV4 } from './helper.js';
|
|
14
|
-
export { GenerateLicenseOptions, JWTLicenseSigner, JWTLicenseSignerOptions } from './jwt-license-signer.js';
|
|
15
|
-
export { JWTLicenseValidator } from './jwt-license-validator.js';
|
|
16
14
|
export { PRIORITIES, activedContentCondition, activedContentRulesConditions, activedRulesConditions, checklistIsDimissed, checklistIsSeen, filterAutoStartContent, findLatestEvent, flowIsDismissed, flowIsSeen, isActive, isActiveContent, isHasActivedContents, isSameContents, isValidContent, isVisible, parseUrlParams, wait } from './conditions.js';
|
|
17
15
|
export { Options, Target, TargetResult, XData, XNode, XResult, finder, finderV2, finderX, parserV2, parserX } from './finderx.js';
|
|
18
16
|
export { default as isEqual } from 'fast-deep-equal';
|
|
@@ -20,4 +18,3 @@ import '@usertour/types';
|
|
|
20
18
|
import './storage.js';
|
|
21
19
|
import '@usertour/types/';
|
|
22
20
|
import 'clsx';
|
|
23
|
-
import 'jsonwebtoken';
|
package/dist/index.js
CHANGED
|
@@ -18,12 +18,6 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
isUrl
|
|
20
20
|
} from "./chunk-ZNFXGN3M.js";
|
|
21
|
-
import {
|
|
22
|
-
JWTLicenseSigner
|
|
23
|
-
} from "./chunk-HWWIAVVP.js";
|
|
24
|
-
import {
|
|
25
|
-
JWTLicenseValidator
|
|
26
|
-
} from "./chunk-Y5PCSFVZ.js";
|
|
27
21
|
import {
|
|
28
22
|
getAuthToken,
|
|
29
23
|
removeAuthToken,
|
|
@@ -137,8 +131,6 @@ import "./chunk-XEO3YXBM.js";
|
|
|
137
131
|
export {
|
|
138
132
|
AbortController,
|
|
139
133
|
ArrayProto,
|
|
140
|
-
JWTLicenseSigner,
|
|
141
|
-
JWTLicenseValidator,
|
|
142
134
|
PRIORITIES,
|
|
143
135
|
XMLHttpRequest,
|
|
144
136
|
absoluteUrl,
|
package/dist/server.cjs
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var __publicField = (obj, key, value) => {
|
|
31
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
32
|
+
return value;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/server.ts
|
|
36
|
+
var server_exports = {};
|
|
37
|
+
__export(server_exports, {
|
|
38
|
+
JWTLicenseSigner: () => JWTLicenseSigner,
|
|
39
|
+
JWTLicenseValidator: () => JWTLicenseValidator
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(server_exports);
|
|
42
|
+
|
|
43
|
+
// src/jwt-license-signer.ts
|
|
44
|
+
var fs = __toESM(require("fs"), 1);
|
|
45
|
+
var path = __toESM(require("path"), 1);
|
|
46
|
+
var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
|
|
47
|
+
var JWTLicenseSigner = class {
|
|
48
|
+
constructor(options) {
|
|
49
|
+
__publicField(this, "privateKey");
|
|
50
|
+
__publicField(this, "issuer");
|
|
51
|
+
__publicField(this, "algorithm");
|
|
52
|
+
this.privateKey = this.loadPrivateKey(options.privateKeyPath);
|
|
53
|
+
this.issuer = options.issuer || "https://www.usertour.io";
|
|
54
|
+
this.algorithm = options.algorithm || "RS256";
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Load RSA private key from file
|
|
58
|
+
*/
|
|
59
|
+
loadPrivateKey(keyPath) {
|
|
60
|
+
try {
|
|
61
|
+
const fullPath = path.resolve(keyPath);
|
|
62
|
+
return fs.readFileSync(fullPath, "utf8");
|
|
63
|
+
} catch (error) {
|
|
64
|
+
throw new Error(`Failed to load private key from ${keyPath}: ${error}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Generate a JWT license token
|
|
69
|
+
*/
|
|
70
|
+
generateLicense(options) {
|
|
71
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
72
|
+
const expiresAt = now + options.expiresInDays * 24 * 60 * 60;
|
|
73
|
+
const payload = {
|
|
74
|
+
plan: options.plan,
|
|
75
|
+
sub: options.subject,
|
|
76
|
+
projectId: options.projectId,
|
|
77
|
+
iat: now,
|
|
78
|
+
exp: expiresAt,
|
|
79
|
+
issuer: options.issuer || this.issuer,
|
|
80
|
+
features: options.features
|
|
81
|
+
};
|
|
82
|
+
try {
|
|
83
|
+
return import_jsonwebtoken.default.sign(payload, this.privateKey, {
|
|
84
|
+
algorithm: this.algorithm,
|
|
85
|
+
issuer: this.issuer
|
|
86
|
+
});
|
|
87
|
+
} catch (error) {
|
|
88
|
+
throw new Error(`Failed to generate JWT license: ${error}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generate a license and return both token and payload info
|
|
93
|
+
*/
|
|
94
|
+
generateLicenseWithInfo(options) {
|
|
95
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
96
|
+
const expiresAt = now + options.expiresInDays * 24 * 60 * 60;
|
|
97
|
+
const payload = {
|
|
98
|
+
plan: options.plan,
|
|
99
|
+
sub: options.subject,
|
|
100
|
+
projectId: options.projectId,
|
|
101
|
+
iat: now,
|
|
102
|
+
exp: expiresAt,
|
|
103
|
+
issuer: options.issuer || this.issuer,
|
|
104
|
+
features: options.features
|
|
105
|
+
};
|
|
106
|
+
const token = import_jsonwebtoken.default.sign(payload, this.privateKey, {
|
|
107
|
+
algorithm: this.algorithm,
|
|
108
|
+
issuer: this.issuer
|
|
109
|
+
});
|
|
110
|
+
return {
|
|
111
|
+
token,
|
|
112
|
+
payload,
|
|
113
|
+
expiresAt: new Date(expiresAt * 1e3)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Decode a JWT token without verification (for debugging)
|
|
118
|
+
*/
|
|
119
|
+
decodeToken(token) {
|
|
120
|
+
try {
|
|
121
|
+
return import_jsonwebtoken.default.decode(token);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error("Failed to decode JWT token:", error);
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get token information without verification
|
|
129
|
+
*/
|
|
130
|
+
getTokenInfo(token) {
|
|
131
|
+
try {
|
|
132
|
+
const decoded = import_jsonwebtoken.default.decode(token, { complete: true });
|
|
133
|
+
if (!decoded || typeof decoded === "string") {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
header: decoded.header,
|
|
138
|
+
payload: decoded.payload,
|
|
139
|
+
signature: decoded.signature
|
|
140
|
+
};
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error("Failed to get token info:", error);
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// src/jwt-license-validator.ts
|
|
149
|
+
var import_jsonwebtoken2 = __toESM(require("jsonwebtoken"), 1);
|
|
150
|
+
var JWTLicenseValidator = {
|
|
151
|
+
/**
|
|
152
|
+
* Validate a JWT license
|
|
153
|
+
* @param license - JWT license string
|
|
154
|
+
* @param publicKey - RSA public key in PEM format
|
|
155
|
+
* @param options - Validation options
|
|
156
|
+
* @returns Validation result
|
|
157
|
+
*/
|
|
158
|
+
validateLicense(license, publicKey, options = {}) {
|
|
159
|
+
try {
|
|
160
|
+
const { checkExpiration = true, currentTime = /* @__PURE__ */ new Date() } = options;
|
|
161
|
+
const decoded = import_jsonwebtoken2.default.verify(license, publicKey, {
|
|
162
|
+
algorithms: ["RS256"],
|
|
163
|
+
ignoreExpiration: !checkExpiration
|
|
164
|
+
});
|
|
165
|
+
const fieldValidation = this.validateRequiredFields(decoded);
|
|
166
|
+
if (!fieldValidation.isValid) {
|
|
167
|
+
return fieldValidation;
|
|
168
|
+
}
|
|
169
|
+
if (checkExpiration) {
|
|
170
|
+
const expirationValidation = this.checkExpiration(decoded, currentTime);
|
|
171
|
+
if (!expirationValidation.isValid) {
|
|
172
|
+
return expirationValidation;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const hasFeature = (feature) => {
|
|
176
|
+
return decoded.features.includes("*") || decoded.features.includes(feature);
|
|
177
|
+
};
|
|
178
|
+
return {
|
|
179
|
+
isValid: true,
|
|
180
|
+
payload: decoded,
|
|
181
|
+
isExpired: false,
|
|
182
|
+
hasFeature
|
|
183
|
+
};
|
|
184
|
+
} catch (error) {
|
|
185
|
+
if (error instanceof import_jsonwebtoken2.default.JsonWebTokenError) {
|
|
186
|
+
return {
|
|
187
|
+
isValid: false,
|
|
188
|
+
error: `JWT validation failed: ${error.message}`
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
if (error instanceof import_jsonwebtoken2.default.TokenExpiredError) {
|
|
192
|
+
return {
|
|
193
|
+
isValid: false,
|
|
194
|
+
error: `License expired: ${error.message}`,
|
|
195
|
+
isExpired: true
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
isValid: false,
|
|
200
|
+
error: `License validation failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
/**
|
|
205
|
+
* Validate that all required fields are present in license payload
|
|
206
|
+
* @param payload - License payload to validate
|
|
207
|
+
* @returns Validation result
|
|
208
|
+
*/
|
|
209
|
+
validateRequiredFields(payload) {
|
|
210
|
+
const requiredFields = ["plan", "sub", "projectId", "iat", "exp", "issuer", "features"];
|
|
211
|
+
for (const field of requiredFields) {
|
|
212
|
+
if (!(field in payload)) {
|
|
213
|
+
return {
|
|
214
|
+
isValid: false,
|
|
215
|
+
error: `Missing required field: ${field}`
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (typeof payload.plan !== "string" || !payload.plan.trim()) {
|
|
220
|
+
return {
|
|
221
|
+
isValid: false,
|
|
222
|
+
error: "Invalid plan: must be a non-empty string"
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (typeof payload.sub !== "string" || !payload.sub.trim()) {
|
|
226
|
+
return {
|
|
227
|
+
isValid: false,
|
|
228
|
+
error: "Invalid sub: must be a non-empty string"
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (typeof payload.projectId !== "string" || !payload.projectId.trim()) {
|
|
232
|
+
return {
|
|
233
|
+
isValid: false,
|
|
234
|
+
error: "Invalid projectId: must be a non-empty string"
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (typeof payload.issuer !== "string" || !payload.issuer.trim()) {
|
|
238
|
+
return {
|
|
239
|
+
isValid: false,
|
|
240
|
+
error: "Invalid issuer: must be a non-empty string"
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
if (!Array.isArray(payload.features)) {
|
|
244
|
+
return {
|
|
245
|
+
isValid: false,
|
|
246
|
+
error: "Invalid features: must be an array"
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
if (typeof payload.iat !== "number" || payload.iat <= 0) {
|
|
250
|
+
return {
|
|
251
|
+
isValid: false,
|
|
252
|
+
error: "Invalid iat: must be a positive number"
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
if (typeof payload.exp !== "number" || payload.exp <= 0) {
|
|
256
|
+
return {
|
|
257
|
+
isValid: false,
|
|
258
|
+
error: "Invalid exp: must be a positive number"
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
if (payload.iat >= payload.exp) {
|
|
262
|
+
return {
|
|
263
|
+
isValid: false,
|
|
264
|
+
error: "Invalid timestamps: iat must be before exp"
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return { isValid: true };
|
|
268
|
+
},
|
|
269
|
+
/**
|
|
270
|
+
* Check if license has expired
|
|
271
|
+
* @param payload - License payload
|
|
272
|
+
* @param currentTime - Current time to check against (defaults to now)
|
|
273
|
+
* @returns Validation result
|
|
274
|
+
*/
|
|
275
|
+
checkExpiration(payload, currentTime = /* @__PURE__ */ new Date()) {
|
|
276
|
+
const now = Math.floor(currentTime.getTime() / 1e3);
|
|
277
|
+
const expiresAt = payload.exp;
|
|
278
|
+
if (now > expiresAt) {
|
|
279
|
+
return {
|
|
280
|
+
isValid: false,
|
|
281
|
+
error: `License expired on ${new Date(expiresAt * 1e3).toISOString()}`,
|
|
282
|
+
isExpired: true
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
return { isValid: true, isExpired: false };
|
|
286
|
+
},
|
|
287
|
+
/**
|
|
288
|
+
* Check if license has a specific feature
|
|
289
|
+
* @param payload - License payload
|
|
290
|
+
* @param feature - Feature to check
|
|
291
|
+
* @returns Whether the feature is available
|
|
292
|
+
*/
|
|
293
|
+
hasFeature(payload, feature) {
|
|
294
|
+
return payload.features.includes("*") || payload.features.includes(feature);
|
|
295
|
+
},
|
|
296
|
+
/**
|
|
297
|
+
* Get license expiration status
|
|
298
|
+
* @param payload - License payload
|
|
299
|
+
* @param currentTime - Current time to check against (defaults to now)
|
|
300
|
+
* @returns Expiration information
|
|
301
|
+
*/
|
|
302
|
+
getExpirationInfo(payload, currentTime = /* @__PURE__ */ new Date()) {
|
|
303
|
+
const now = Math.floor(currentTime.getTime() / 1e3);
|
|
304
|
+
const expiresAt = payload.exp;
|
|
305
|
+
const isExpired = now > expiresAt;
|
|
306
|
+
const daysUntilExpiration = Math.ceil((expiresAt - now) / (24 * 60 * 60));
|
|
307
|
+
return {
|
|
308
|
+
isExpired,
|
|
309
|
+
expiresAt: new Date(expiresAt * 1e3),
|
|
310
|
+
daysUntilExpiration: isExpired ? 0 : daysUntilExpiration
|
|
311
|
+
};
|
|
312
|
+
},
|
|
313
|
+
/**
|
|
314
|
+
* Decode JWT license without verification (for debugging)
|
|
315
|
+
* @param license - JWT license string
|
|
316
|
+
* @returns Decoded payload or null if invalid
|
|
317
|
+
*/
|
|
318
|
+
decodeLicense(license) {
|
|
319
|
+
try {
|
|
320
|
+
const decoded = import_jsonwebtoken2.default.decode(license);
|
|
321
|
+
return decoded;
|
|
322
|
+
} catch {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
328
|
+
0 && (module.exports = {
|
|
329
|
+
JWTLicenseSigner,
|
|
330
|
+
JWTLicenseValidator
|
|
331
|
+
});
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usertour/helpers",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Utility functions and helpers shared across the UserTour project",
|
|
6
6
|
"homepage": "https://www.usertour.io",
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
"import": "./dist/index.js",
|
|
15
15
|
"require": "./dist/index.js",
|
|
16
16
|
"types": "./dist/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./server": {
|
|
19
|
+
"import": "./dist/server.js",
|
|
20
|
+
"require": "./dist/server.js",
|
|
21
|
+
"types": "./dist/server.d.ts"
|
|
17
22
|
}
|
|
18
23
|
},
|
|
19
24
|
"files": ["dist"],
|