@unloq/unloq-code-validtor 1.0.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/dist/__tests__/index.test.d.ts +1 -0
- package/dist/__tests__/index.test.js +151 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +128 -0
- package/dist/interface/reason.d.ts +14 -0
- package/dist/interface/reason.js +21 -0
- package/dist/utils/hash.d.ts +21 -0
- package/dist/utils/hash.js +44 -0
- package/dist/utils/string.d.ts +6 -0
- package/dist/utils/string.js +21 -0
- package/package.json +35 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { validateUnloqDiscountCode } from '../index';
|
|
2
|
+
import { Reason } from '../interface/reason';
|
|
3
|
+
import { getSHA256Hash } from '../utils/hash';
|
|
4
|
+
describe('validateGiftCardCode', () => {
|
|
5
|
+
const tests = [
|
|
6
|
+
{
|
|
7
|
+
name: "invalid fealtyx code, first 2 of last 4 characters don't match last 2",
|
|
8
|
+
domain: "example.com",
|
|
9
|
+
phoneNumber: "+918989898989",
|
|
10
|
+
giftCardCode: "FLX1234ABCD",
|
|
11
|
+
orderAmount: 100.0,
|
|
12
|
+
is_applicable: true,
|
|
13
|
+
is_unloq_discount_code: false,
|
|
14
|
+
reason: null
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "invalid fealtyx code - missing prefix",
|
|
18
|
+
domain: "example.com",
|
|
19
|
+
phoneNumber: "+918989898989",
|
|
20
|
+
giftCardCode: "123415EG",
|
|
21
|
+
orderAmount: 100.0,
|
|
22
|
+
is_applicable: true,
|
|
23
|
+
is_unloq_discount_code: false,
|
|
24
|
+
reason: null
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "invalid fealtyx code - short code",
|
|
28
|
+
domain: "example.com",
|
|
29
|
+
phoneNumber: "+918989898989",
|
|
30
|
+
giftCardCode: "FL1",
|
|
31
|
+
orderAmount: 100.0,
|
|
32
|
+
is_applicable: true,
|
|
33
|
+
is_unloq_discount_code: false,
|
|
34
|
+
reason: null
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "valid fealtyx code - domain mismatch",
|
|
38
|
+
domain: "example2.com",
|
|
39
|
+
phoneNumber: "+918989898989",
|
|
40
|
+
giftCardCode: "FLX123415EG",
|
|
41
|
+
orderAmount: 100.0,
|
|
42
|
+
is_applicable: false,
|
|
43
|
+
is_unloq_discount_code: true,
|
|
44
|
+
reason: Reason.VoucherNotEligible
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "valid fealtyx code - phone mismatch",
|
|
48
|
+
domain: "example.com",
|
|
49
|
+
phoneNumber: "777777",
|
|
50
|
+
giftCardCode: "FLX123415EG",
|
|
51
|
+
orderAmount: 100.0,
|
|
52
|
+
is_applicable: false,
|
|
53
|
+
is_unloq_discount_code: true,
|
|
54
|
+
reason: Reason.VoucherNotEligible
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "valid fealtyx code with FLX prefix",
|
|
58
|
+
domain: "example.com",
|
|
59
|
+
phoneNumber: "+918989898989",
|
|
60
|
+
giftCardCode: "FLX123415EG",
|
|
61
|
+
orderAmount: 100.0,
|
|
62
|
+
is_applicable: true,
|
|
63
|
+
is_unloq_discount_code: true,
|
|
64
|
+
reason: null
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "valid fealtyx code with UNQ prefix",
|
|
68
|
+
domain: "example.com",
|
|
69
|
+
phoneNumber: "+918989898989",
|
|
70
|
+
giftCardCode: "UNQ123415EG",
|
|
71
|
+
orderAmount: 100.0,
|
|
72
|
+
is_applicable: true,
|
|
73
|
+
is_unloq_discount_code: true,
|
|
74
|
+
reason: null
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "valid fealtyx code with hashed phone",
|
|
78
|
+
domain: "example.com",
|
|
79
|
+
phoneNumber: getSHA256Hash("+918989898989"),
|
|
80
|
+
giftCardCode: "FLX123415EG",
|
|
81
|
+
orderAmount: 100.0,
|
|
82
|
+
is_applicable: true,
|
|
83
|
+
is_unloq_discount_code: true,
|
|
84
|
+
reason: null
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "valid fealtyx code with non hashed phone",
|
|
88
|
+
domain: "example.com",
|
|
89
|
+
phoneNumber: "+918989898989",
|
|
90
|
+
giftCardCode: "FLX123415EG",
|
|
91
|
+
orderAmount: 100.0,
|
|
92
|
+
is_applicable: true,
|
|
93
|
+
is_unloq_discount_code: true,
|
|
94
|
+
reason: null
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "valid fealtyx code with hashed phone but no order amount",
|
|
98
|
+
domain: "example.com",
|
|
99
|
+
phoneNumber: getSHA256Hash("+918989898989"),
|
|
100
|
+
giftCardCode: "FLX123415EG",
|
|
101
|
+
orderAmount: 0,
|
|
102
|
+
is_applicable: true,
|
|
103
|
+
is_unloq_discount_code: true,
|
|
104
|
+
reason: null
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "valid fealtyx code with hashed phone but empty domain",
|
|
108
|
+
domain: "",
|
|
109
|
+
phoneNumber: getSHA256Hash("+918989898989"),
|
|
110
|
+
giftCardCode: "FLX123415EG",
|
|
111
|
+
orderAmount: 100.0,
|
|
112
|
+
is_applicable: false,
|
|
113
|
+
is_unloq_discount_code: true,
|
|
114
|
+
reason: Reason.InvalidDomain
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "valid fealtyx code with hashed phone but invalid domain",
|
|
118
|
+
domain: "example\x00.com",
|
|
119
|
+
phoneNumber: getSHA256Hash("+918989898989"),
|
|
120
|
+
giftCardCode: "FLX123415EG",
|
|
121
|
+
orderAmount: 100.0,
|
|
122
|
+
is_applicable: false,
|
|
123
|
+
is_unloq_discount_code: true,
|
|
124
|
+
reason: Reason.InvalidDomain
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "non-fealtyx code",
|
|
128
|
+
domain: "example.com",
|
|
129
|
+
phoneNumber: "+918989898989",
|
|
130
|
+
giftCardCode: "ABCD1234EFGH",
|
|
131
|
+
orderAmount: 100.0,
|
|
132
|
+
is_applicable: true,
|
|
133
|
+
is_unloq_discount_code: false,
|
|
134
|
+
reason: null
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
tests.forEach(testCase => {
|
|
138
|
+
it(testCase.name, () => {
|
|
139
|
+
const result = validateUnloqDiscountCode(testCase.domain, testCase.phoneNumber, testCase.giftCardCode, testCase.orderAmount);
|
|
140
|
+
expect(result.is_applicable).toBe(testCase.is_applicable);
|
|
141
|
+
expect(result.is_unloq_discount_code).toBe(testCase.is_unloq_discount_code);
|
|
142
|
+
// Handle both string and Reason enum comparison
|
|
143
|
+
if (testCase.reason === null) {
|
|
144
|
+
expect(result.reason).toBeNull();
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
expect(result.reason).toBe(testCase.reason);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Reason } from "./interface/reason";
|
|
2
|
+
export type ValidationResult = {
|
|
3
|
+
is_applicable: boolean;
|
|
4
|
+
is_unloq_discount_code: boolean;
|
|
5
|
+
reason: Reason | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function validateUnloqDiscountCode(domain: string, phoneNumber: string, giftCardCode: string, orderAmount: number): ValidationResult;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Reason } from "./interface/reason";
|
|
2
|
+
import { getSHA256Hash, getPhoneNumberHash } from "./utils/hash";
|
|
3
|
+
import { hexCharToByte } from "./utils/string";
|
|
4
|
+
export function validateUnloqDiscountCode(domain, phoneNumber, giftCardCode, orderAmount) {
|
|
5
|
+
// First, clean the gift card code
|
|
6
|
+
giftCardCode = giftCardCode.toLowerCase().trim();
|
|
7
|
+
// If gift card code is too short, return
|
|
8
|
+
if (!giftCardCode || giftCardCode.length < 4) {
|
|
9
|
+
return {
|
|
10
|
+
is_applicable: true,
|
|
11
|
+
is_unloq_discount_code: false,
|
|
12
|
+
reason: null,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
// Check if gift card code starts with "flx" or "unq"
|
|
16
|
+
if (!giftCardCode.startsWith("flx") && !giftCardCode.startsWith("unq")) {
|
|
17
|
+
return {
|
|
18
|
+
is_applicable: true,
|
|
19
|
+
is_unloq_discount_code: false,
|
|
20
|
+
reason: null,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// Get last 4 characters of the code
|
|
24
|
+
const last4 = giftCardCode.slice(-4);
|
|
25
|
+
if (last4.length !== 4) {
|
|
26
|
+
return {
|
|
27
|
+
is_applicable: true,
|
|
28
|
+
is_unloq_discount_code: false,
|
|
29
|
+
reason: null,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const first2 = last4.slice(0, 2);
|
|
33
|
+
const actualLast2 = last4.slice(2);
|
|
34
|
+
// Step 1: Check if this is an Fealtyx gift card by checking if the last 2 characters match the expected last 2 characters
|
|
35
|
+
const expectedLast2 = generateLast2FromFirst2(first2);
|
|
36
|
+
if (actualLast2 !== expectedLast2) {
|
|
37
|
+
// If the last 2 don't match the expected pattern, the gift card is not a Fealtyx gift card
|
|
38
|
+
return {
|
|
39
|
+
is_applicable: true,
|
|
40
|
+
is_unloq_discount_code: false,
|
|
41
|
+
reason: null,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Sanitize domain
|
|
45
|
+
const { result: sanitizedDomain, error: err } = sanitizeDomain(domain);
|
|
46
|
+
if (err !== null) {
|
|
47
|
+
return {
|
|
48
|
+
is_applicable: false,
|
|
49
|
+
is_unloq_discount_code: true,
|
|
50
|
+
reason: Reason.InvalidDomain,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Step 2: Verify full code - generate expected suffix
|
|
54
|
+
const expectedSuffix = getGiftCardCodeIdentifier(sanitizedDomain, phoneNumber).toLowerCase();
|
|
55
|
+
// Case-insensitive match
|
|
56
|
+
const valid = expectedSuffix.toLowerCase() === last4.toLowerCase();
|
|
57
|
+
if (!valid) {
|
|
58
|
+
return {
|
|
59
|
+
is_applicable: false,
|
|
60
|
+
is_unloq_discount_code: true,
|
|
61
|
+
reason: Reason.VoucherNotEligible,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
is_applicable: true,
|
|
66
|
+
is_unloq_discount_code: true,
|
|
67
|
+
reason: null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// Helper function to generate last 2 characters from first 2 characters
|
|
71
|
+
function generateLast2FromFirst2(first2) {
|
|
72
|
+
const alphanum = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
73
|
+
const charsetLen = alphanum.length;
|
|
74
|
+
if (first2.length !== 2) {
|
|
75
|
+
return "";
|
|
76
|
+
}
|
|
77
|
+
// Convert hex characters to numeric byte values
|
|
78
|
+
const c1 = first2[0];
|
|
79
|
+
const c2 = first2[1];
|
|
80
|
+
const b1 = hexCharToByte(c1);
|
|
81
|
+
const b2 = hexCharToByte(c2);
|
|
82
|
+
// Get XOR and sum of first 2 characters
|
|
83
|
+
const xor = b1 ^ b2;
|
|
84
|
+
const sum = b1 + b2;
|
|
85
|
+
// Map XOR and sum results to character set
|
|
86
|
+
const idx1 = xor % charsetLen;
|
|
87
|
+
const idx2 = sum % charsetLen;
|
|
88
|
+
return alphanum[idx1] + alphanum[idx2];
|
|
89
|
+
}
|
|
90
|
+
function getGiftCardCodeIdentifier(partnerEntityId, phoneNumber) {
|
|
91
|
+
let hashedPhoneNumber;
|
|
92
|
+
hashedPhoneNumber = getPhoneNumberHash(phoneNumber);
|
|
93
|
+
const alphanum = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
94
|
+
const charsetLen = alphanum.length;
|
|
95
|
+
let input = (partnerEntityId + hashedPhoneNumber).toLowerCase();
|
|
96
|
+
const hash = getSHA256Hash(input);
|
|
97
|
+
const c1 = hash[0];
|
|
98
|
+
const c2 = hash[1];
|
|
99
|
+
const b1 = hexCharToByte(c1);
|
|
100
|
+
const b2 = hexCharToByte(c2);
|
|
101
|
+
const xor = b1 ^ b2;
|
|
102
|
+
const idx1 = xor % charsetLen;
|
|
103
|
+
const idx2 = (b1 + b2) % charsetLen;
|
|
104
|
+
return `${c1}${c2}${alphanum[idx1]}${alphanum[idx2]}`;
|
|
105
|
+
}
|
|
106
|
+
function sanitizeDomain(input) {
|
|
107
|
+
input = input.trim();
|
|
108
|
+
// Add scheme if missing to make it a valid URL
|
|
109
|
+
if (!input.includes('://')) {
|
|
110
|
+
input = 'https://' + input;
|
|
111
|
+
}
|
|
112
|
+
let parsed;
|
|
113
|
+
try {
|
|
114
|
+
parsed = new URL(input);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
return {
|
|
118
|
+
result: '',
|
|
119
|
+
error: new Error(`invalid domain: ${err instanceof Error ? err.message : String(err)}`)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Extract host and convert to lowercase
|
|
123
|
+
const domain = parsed.hostname.toLowerCase();
|
|
124
|
+
if (!domain) {
|
|
125
|
+
return { result: '', error: new Error('empty domain') };
|
|
126
|
+
}
|
|
127
|
+
return { result: domain, error: null };
|
|
128
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare enum Reason {
|
|
2
|
+
CodeTooShort = "Code Too Short",
|
|
3
|
+
InvalidDomain = "Invalid Domain",
|
|
4
|
+
VoucherNotEligible = "Voucher Not Eligible For The User",
|
|
5
|
+
InvalidPhone = "Invalid Phone Number",
|
|
6
|
+
InvalidOrderAmount = "Invalid Order Amount"
|
|
7
|
+
}
|
|
8
|
+
export declare namespace Reason {
|
|
9
|
+
/**
|
|
10
|
+
* Returns the string representation of a Reason.
|
|
11
|
+
* If the input is empty/undefined/null, returns Reason.Unknown.
|
|
12
|
+
*/
|
|
13
|
+
function String(r?: Reason | string | null): string | null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export var Reason;
|
|
2
|
+
(function (Reason) {
|
|
3
|
+
Reason["CodeTooShort"] = "Code Too Short";
|
|
4
|
+
Reason["InvalidDomain"] = "Invalid Domain";
|
|
5
|
+
Reason["VoucherNotEligible"] = "Voucher Not Eligible For The User";
|
|
6
|
+
Reason["InvalidPhone"] = "Invalid Phone Number";
|
|
7
|
+
Reason["InvalidOrderAmount"] = "Invalid Order Amount";
|
|
8
|
+
})(Reason || (Reason = {}));
|
|
9
|
+
(function (Reason) {
|
|
10
|
+
/**
|
|
11
|
+
* Returns the string representation of a Reason.
|
|
12
|
+
* If the input is empty/undefined/null, returns Reason.Unknown.
|
|
13
|
+
*/
|
|
14
|
+
function String(r) {
|
|
15
|
+
if (r === undefined || r === null || r === "") {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return String(r);
|
|
19
|
+
}
|
|
20
|
+
Reason.String = String;
|
|
21
|
+
})(Reason || (Reason = {}));
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the SHA-256 hash of the input string.
|
|
3
|
+
* If the input string is already hashed, returns the string as it is.
|
|
4
|
+
* @param s - The string to hash
|
|
5
|
+
* @returns The SHA-256 hash of the input string
|
|
6
|
+
*/
|
|
7
|
+
export declare function getSHA256Hash(s: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Checks if the input string is a SHA-256 hash.
|
|
10
|
+
* @param s - The string to check
|
|
11
|
+
* @returns True if the string is a SHA-256 hash, false otherwise
|
|
12
|
+
*/
|
|
13
|
+
export declare function isSHA256Hash(s: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Generates SHA256 hash for phone number.
|
|
16
|
+
* If the phone number doesn't start with +91, adds +91.
|
|
17
|
+
* If the phone number is already hashed, returns the string as it is.
|
|
18
|
+
* @param phoneNum - The phone number to hash
|
|
19
|
+
* @returns The SHA-256 hash of the phone number
|
|
20
|
+
*/
|
|
21
|
+
export declare function getPhoneNumberHash(phoneNum: string): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as crypto from 'crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the SHA-256 hash of the input string.
|
|
4
|
+
* If the input string is already hashed, returns the string as it is.
|
|
5
|
+
* @param s - The string to hash
|
|
6
|
+
* @returns The SHA-256 hash of the input string
|
|
7
|
+
*/
|
|
8
|
+
export function getSHA256Hash(s) {
|
|
9
|
+
if (s === '' || isSHA256Hash(s)) {
|
|
10
|
+
return s;
|
|
11
|
+
}
|
|
12
|
+
// Create a new SHA-256 hash
|
|
13
|
+
const hash = crypto.createHash('sha256');
|
|
14
|
+
// Update the hash with the input string
|
|
15
|
+
hash.update(s);
|
|
16
|
+
// Get the hash as a hexadecimal string
|
|
17
|
+
return hash.digest('hex');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Checks if the input string is a SHA-256 hash.
|
|
21
|
+
* @param s - The string to check
|
|
22
|
+
* @returns True if the string is a SHA-256 hash, false otherwise
|
|
23
|
+
*/
|
|
24
|
+
export function isSHA256Hash(s) {
|
|
25
|
+
// SHA-256 hash: 64-character hexadecimal string
|
|
26
|
+
const sha256Regex = /^[a-fA-F0-9]{64}$/;
|
|
27
|
+
return sha256Regex.test(s);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generates SHA256 hash for phone number.
|
|
31
|
+
* If the phone number doesn't start with +91, adds +91.
|
|
32
|
+
* If the phone number is already hashed, returns the string as it is.
|
|
33
|
+
* @param phoneNum - The phone number to hash
|
|
34
|
+
* @returns The SHA-256 hash of the phone number
|
|
35
|
+
*/
|
|
36
|
+
export function getPhoneNumberHash(phoneNum) {
|
|
37
|
+
if (phoneNum === '' || isSHA256Hash(phoneNum)) {
|
|
38
|
+
return phoneNum;
|
|
39
|
+
}
|
|
40
|
+
if (phoneNum.startsWith('+91')) {
|
|
41
|
+
return getSHA256Hash(phoneNum);
|
|
42
|
+
}
|
|
43
|
+
return getSHA256Hash('+91' + phoneNum);
|
|
44
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a hex character ('0'-'9', 'a'-'f', 'A'-'F') to a number between 0-15
|
|
3
|
+
* @param c - The hex character to convert
|
|
4
|
+
* @returns A number between 0-15 representing the hex value, or 0 if the character is invalid
|
|
5
|
+
*/
|
|
6
|
+
export declare function hexCharToByte(c: string): number;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a hex character ('0'-'9', 'a'-'f', 'A'-'F') to a number between 0-15
|
|
3
|
+
* @param c - The hex character to convert
|
|
4
|
+
* @returns A number between 0-15 representing the hex value, or 0 if the character is invalid
|
|
5
|
+
*/
|
|
6
|
+
export function hexCharToByte(c) {
|
|
7
|
+
// Ensure we only process the first character if a longer string is passed
|
|
8
|
+
const char = c.charAt(0);
|
|
9
|
+
if (char >= '0' && char <= '9') {
|
|
10
|
+
return char.charCodeAt(0) - '0'.charCodeAt(0);
|
|
11
|
+
}
|
|
12
|
+
else if (char >= 'a' && char <= 'f') {
|
|
13
|
+
return char.charCodeAt(0) - 'a'.charCodeAt(0) + 10;
|
|
14
|
+
}
|
|
15
|
+
else if (char >= 'A' && char <= 'F') {
|
|
16
|
+
return char.charCodeAt(0) - 'A'.charCodeAt(0) + 10;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unloq/unloq-code-validtor",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/fealtyx/unloq-nodejs"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/fealtyx/unloq-nodejs",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/fealtyx/unloq-nodejs/issues"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"test": "jest",
|
|
20
|
+
"test:watch": "jest --watch"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"crypto": "^1.0.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/jest": "^30.0.0",
|
|
31
|
+
"@types/node": "^24.10.0",
|
|
32
|
+
"jest": "^30.2.0",
|
|
33
|
+
"ts-jest": "^29.4.5"
|
|
34
|
+
}
|
|
35
|
+
}
|