@ripwords/myinvois-client 0.2.41 → 0.3.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/apiQueue-B6Q644Bz.js +201 -0
- package/dist/apiQueue-DgKWaQDS.cjs +220 -0
- package/dist/apiQueue-DgKWaQDS.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index10.cjs +24 -4
- package/dist/index10.cjs.map +1 -0
- package/dist/index11.cjs +0 -22
- package/dist/index12.cjs +33 -2
- package/dist/index12.cjs.map +1 -0
- package/dist/index13.cjs +23 -2
- package/dist/index13.cjs.map +1 -0
- package/dist/index14.cjs +0 -330
- package/dist/index15.cjs +0 -193
- package/dist/index16.cjs +0 -62
- package/dist/index17.cjs +4 -531
- package/dist/index18.cjs +6 -195
- package/dist/index19.cjs +5 -0
- package/dist/index2.cjs +61 -4
- package/dist/index2.cjs.map +1 -0
- package/dist/index20.cjs +2 -24
- package/dist/index21.cjs +3 -0
- package/dist/index22.cjs +6 -0
- package/dist/index23.cjs +203 -24
- package/dist/index23.cjs.map +1 -1
- package/dist/index24.cjs +104 -20
- package/dist/index24.cjs.map +1 -1
- package/dist/index25.cjs +137 -0
- package/dist/index25.cjs.map +1 -0
- package/dist/index26.cjs +59 -29
- package/dist/index26.cjs.map +1 -1
- package/dist/index27.cjs +262 -19
- package/dist/index27.cjs.map +1 -1
- package/dist/index28.cjs +79 -0
- package/dist/index28.cjs.map +1 -0
- package/dist/index29.cjs +107 -0
- package/dist/index29.cjs.map +1 -0
- package/dist/index3.cjs +531 -6
- package/dist/index3.cjs.map +1 -0
- package/dist/index30.cjs +73 -0
- package/dist/index30.cjs.map +1 -0
- package/dist/index31.cjs +107 -203
- package/dist/index31.cjs.map +1 -1
- package/dist/index32.cjs +95 -104
- package/dist/index32.cjs.map +1 -1
- package/dist/index33.cjs +13 -132
- package/dist/index33.cjs.map +1 -1
- package/dist/index34.cjs +33 -59
- package/dist/index34.cjs.map +1 -1
- package/dist/index35.cjs +14 -262
- package/dist/index35.cjs.map +1 -1
- package/dist/index36.cjs +24 -74
- package/dist/index36.cjs.map +1 -1
- package/dist/index37.cjs +15 -102
- package/dist/index37.cjs.map +1 -1
- package/dist/index38.cjs +9 -68
- package/dist/index38.cjs.map +1 -1
- package/dist/index39.cjs +9 -107
- package/dist/index39.cjs.map +1 -1
- package/dist/index4.cjs +195 -4
- package/dist/index4.cjs.map +1 -0
- package/dist/index40.cjs +12 -95
- package/dist/index40.cjs.map +1 -1
- package/dist/index41.cjs +6 -11
- package/dist/index41.cjs.map +1 -1
- package/dist/index42.cjs +101 -31
- package/dist/index42.cjs.map +1 -1
- package/dist/index43.cjs +106 -12
- package/dist/index43.cjs.map +1 -1
- package/dist/index44.cjs +119 -22
- package/dist/index44.cjs.map +1 -1
- package/dist/index45.cjs +106 -13
- package/dist/index45.cjs.map +1 -1
- package/dist/index46.cjs +98 -7
- package/dist/index46.cjs.map +1 -1
- package/dist/index47.cjs +118 -7
- package/dist/index47.cjs.map +1 -1
- package/dist/index48.cjs +127 -10
- package/dist/index48.cjs.map +1 -1
- package/dist/index49.cjs +117 -6
- package/dist/index49.cjs.map +1 -1
- package/dist/index5.cjs +0 -3
- package/dist/index50.cjs +14 -101
- package/dist/index50.cjs.map +1 -1
- package/dist/index51.cjs +95 -106
- package/dist/index51.cjs.map +1 -1
- package/dist/index52.cjs +142 -119
- package/dist/index52.cjs.map +1 -1
- package/dist/index53.cjs +114 -106
- package/dist/index53.cjs.map +1 -1
- package/dist/index54.cjs +144 -98
- package/dist/index54.cjs.map +1 -1
- package/dist/index55.cjs +113 -118
- package/dist/index55.cjs.map +1 -1
- package/dist/index56.cjs +17 -127
- package/dist/index56.cjs.map +1 -1
- package/dist/index57.cjs +112 -117
- package/dist/index57.cjs.map +1 -1
- package/dist/index58.cjs +47 -14
- package/dist/index58.cjs.map +1 -1
- package/dist/index59.cjs +14 -95
- package/dist/index59.cjs.map +1 -1
- package/dist/index6.cjs +24 -2
- package/dist/index6.cjs.map +1 -0
- package/dist/index60.cjs +28 -142
- package/dist/index60.cjs.map +1 -1
- package/dist/index61.cjs +22 -114
- package/dist/index61.cjs.map +1 -1
- package/dist/index62.cjs +9 -144
- package/dist/index62.cjs.map +1 -1
- package/dist/index63.cjs +8 -113
- package/dist/index63.cjs.map +1 -1
- package/dist/index64.cjs +17 -17
- package/dist/index64.cjs.map +1 -1
- package/dist/index65.cjs +412 -112
- package/dist/index65.cjs.map +1 -1
- package/dist/index66.cjs +8 -47
- package/dist/index66.cjs.map +1 -1
- package/dist/index67.cjs +9 -14
- package/dist/index67.cjs.map +1 -1
- package/dist/index68.cjs +4 -34
- package/dist/index68.cts.map +1 -1
- package/dist/index69.cjs +9 -25
- package/dist/index69.cjs.map +1 -1
- package/dist/index7.cjs +0 -6
- package/dist/index70.cjs +4 -15
- package/dist/index71.cjs +21 -14
- package/dist/index72.cjs +2 -23
- package/dist/index73.cjs +2 -418
- package/dist/index74.cjs +324 -9
- package/dist/index74.cjs.map +1 -1
- package/dist/index75.cjs +187 -10
- package/dist/index75.cjs.map +1 -1
- package/dist/index8.cjs +0 -4
- package/dist/index9.cjs +25 -9
- package/dist/index9.cjs.map +1 -1
- package/dist/utils/apiQueue.d.ts +11 -3
- package/dist/utils/apiQueue.js +2 -2
- package/package.json +1 -1
- package/dist/apiQueue-CCrZMnMu.js +0 -182
- package/dist/apiQueue-Djd7WlnV.cjs +0 -195
- package/dist/apiQueue-Djd7WlnV.cjs.map +0 -1
- package/dist/index14.cjs.map +0 -1
- package/dist/index15.cjs.map +0 -1
- package/dist/index16.cjs.map +0 -1
- package/dist/index17.cjs.map +0 -1
- package/dist/index18.cjs.map +0 -1
- package/dist/index20.cjs.map +0 -1
- package/dist/index68.cjs.map +0 -1
- package/dist/index70.cjs.map +0 -1
- package/dist/index71.cjs.map +0 -1
- package/dist/index72.cjs.map +0 -1
- package/dist/index73.cjs.map +0 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
//#region src/utils/apiQueue.ts
|
|
2
|
+
const queues = {};
|
|
3
|
+
const LIMITS = {
|
|
4
|
+
loginTaxpayer: {
|
|
5
|
+
max: 12,
|
|
6
|
+
perMs: 6e4
|
|
7
|
+
},
|
|
8
|
+
loginIntermediary: {
|
|
9
|
+
max: 12,
|
|
10
|
+
perMs: 6e4
|
|
11
|
+
},
|
|
12
|
+
submitDocuments: {
|
|
13
|
+
max: 100,
|
|
14
|
+
perMs: 6e4
|
|
15
|
+
},
|
|
16
|
+
getSubmission: {
|
|
17
|
+
max: 300,
|
|
18
|
+
perMs: 6e4
|
|
19
|
+
},
|
|
20
|
+
cancelDocument: {
|
|
21
|
+
max: 12,
|
|
22
|
+
perMs: 6e4
|
|
23
|
+
},
|
|
24
|
+
rejectDocument: {
|
|
25
|
+
max: 12,
|
|
26
|
+
perMs: 6e4
|
|
27
|
+
},
|
|
28
|
+
getDocument: {
|
|
29
|
+
max: 60,
|
|
30
|
+
perMs: 6e4
|
|
31
|
+
},
|
|
32
|
+
getDocumentDetails: {
|
|
33
|
+
max: 125,
|
|
34
|
+
perMs: 6e4
|
|
35
|
+
},
|
|
36
|
+
getRecentDocuments: {
|
|
37
|
+
max: 12,
|
|
38
|
+
perMs: 6e4
|
|
39
|
+
},
|
|
40
|
+
searchDocuments: {
|
|
41
|
+
max: 12,
|
|
42
|
+
perMs: 6e4
|
|
43
|
+
},
|
|
44
|
+
searchTin: {
|
|
45
|
+
max: 60,
|
|
46
|
+
perMs: 6e4
|
|
47
|
+
},
|
|
48
|
+
taxpayerQr: {
|
|
49
|
+
max: 60,
|
|
50
|
+
perMs: 6e4
|
|
51
|
+
},
|
|
52
|
+
default: {
|
|
53
|
+
max: 12,
|
|
54
|
+
perMs: 6e4
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Clean up old timestamps outside the sliding window
|
|
59
|
+
*/
|
|
60
|
+
function cleanupTimestamps(timestamps, windowMs, now) {
|
|
61
|
+
return timestamps.filter((ts) => now - ts < windowMs);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Calculate when we can make the next request without exceeding the rate limit
|
|
65
|
+
*/
|
|
66
|
+
function getNextAvailableTime(timestamps, max, windowMs, now) {
|
|
67
|
+
if (timestamps.length < max) return now;
|
|
68
|
+
const oldestTimestamp = timestamps[0];
|
|
69
|
+
if (!oldestTimestamp) return now;
|
|
70
|
+
return oldestTimestamp + windowMs;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Public helper to schedule a request according to the category's limits.
|
|
74
|
+
* Rate limits are enforced per clientId, so multiple instances with the same
|
|
75
|
+
* clientId will share rate limiters, while different clientIds get separate limiters.
|
|
76
|
+
*
|
|
77
|
+
* This implementation uses a sliding window to track all requests within the time window.
|
|
78
|
+
*/
|
|
79
|
+
function queueRequest(clientId, category, task, debug = false) {
|
|
80
|
+
const key = `${clientId}:${category}`;
|
|
81
|
+
if (!queues[key]) queues[key] = {
|
|
82
|
+
running: 0,
|
|
83
|
+
queue: [],
|
|
84
|
+
requestTimestamps: [],
|
|
85
|
+
nextTimer: null
|
|
86
|
+
};
|
|
87
|
+
const queue = queues[key];
|
|
88
|
+
const { max, perMs } = LIMITS[category] ?? LIMITS.default;
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
const run = () => {
|
|
91
|
+
const now$1 = Date.now();
|
|
92
|
+
queue.requestTimestamps = cleanupTimestamps(queue.requestTimestamps, perMs, now$1);
|
|
93
|
+
if (queue.requestTimestamps.length >= max) {
|
|
94
|
+
const nextAvailable = getNextAvailableTime(queue.requestTimestamps, max, perMs, now$1);
|
|
95
|
+
const waitTime = nextAvailable - now$1;
|
|
96
|
+
if (debug) console.log(`[apiQueue] 🚫 Rate limit reached (${queue.requestTimestamps.length}/${max} in last ${perMs}ms). Queuing request. Need to wait ${waitTime.toFixed(0)}ms. Queue size: ${queue.queue.length + 1}`);
|
|
97
|
+
queue.queue.push({
|
|
98
|
+
run,
|
|
99
|
+
addedAt: now$1
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
queue.requestTimestamps.push(now$1);
|
|
104
|
+
queue.running++;
|
|
105
|
+
if (debug) console.log(`[apiQueue] ▶️ Executing request (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Running: ${queue.running}. Queue size: ${queue.queue.length}`);
|
|
106
|
+
task().then(resolve).catch(reject).finally(() => {
|
|
107
|
+
queue.running--;
|
|
108
|
+
if (debug) console.log(`[apiQueue] ✅ Request completed (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Running: ${queue.running}. Queue size: ${queue.queue.length}`);
|
|
109
|
+
processQueue(key, debug, category);
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
const now = Date.now();
|
|
113
|
+
queue.requestTimestamps = cleanupTimestamps(queue.requestTimestamps, perMs, now);
|
|
114
|
+
if (queue.queue.length > 0 || queue.requestTimestamps.length >= max) {
|
|
115
|
+
queue.queue.push({
|
|
116
|
+
run,
|
|
117
|
+
addedAt: now
|
|
118
|
+
});
|
|
119
|
+
if (debug) console.log(`[apiQueue] ⏳ Queued request (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Queue size: ${queue.queue.length}`);
|
|
120
|
+
processQueue(key, debug, category);
|
|
121
|
+
} else run();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function processQueue(key, debug, category) {
|
|
125
|
+
const queue = queues[key];
|
|
126
|
+
if (!queue || queue.queue.length === 0) return;
|
|
127
|
+
const { max, perMs } = LIMITS[category] ?? LIMITS.default;
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
queue.requestTimestamps = cleanupTimestamps(queue.requestTimestamps, perMs, now);
|
|
130
|
+
if (queue.requestTimestamps.length < max) {
|
|
131
|
+
const next = queue.queue.shift();
|
|
132
|
+
if (next) {
|
|
133
|
+
if (debug) {
|
|
134
|
+
const waitTime = Date.now() - next.addedAt;
|
|
135
|
+
console.log(`[apiQueue] 🚀 Processing queued request (${category}). Waited: ${waitTime.toFixed(0)}ms. Queue size: ${queue.queue.length}`);
|
|
136
|
+
}
|
|
137
|
+
next.run();
|
|
138
|
+
}
|
|
139
|
+
if (queue.queue.length > 0) processQueue(key, debug, category);
|
|
140
|
+
} else {
|
|
141
|
+
const nextAvailable = getNextAvailableTime(queue.requestTimestamps, max, perMs, now);
|
|
142
|
+
const delay = Math.max(0, nextAvailable - now + 50);
|
|
143
|
+
if (debug) console.log(`[apiQueue] ⏸️ Delaying queue processing (${category}). Will retry in ${delay.toFixed(0)}ms. Queue size: ${queue.queue.length}`);
|
|
144
|
+
if (!queue.nextTimer) queue.nextTimer = setTimeout(() => {
|
|
145
|
+
queue.nextTimer = null;
|
|
146
|
+
processQueue(key, debug, category);
|
|
147
|
+
}, delay);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Cleanup function to clear all queues and timers for a specific client.
|
|
152
|
+
* Useful for testing or cleanup on application shutdown.
|
|
153
|
+
*/
|
|
154
|
+
function clearQueue(clientId, category) {
|
|
155
|
+
if (category) {
|
|
156
|
+
const key = `${clientId}:${category}`;
|
|
157
|
+
const queue = queues[key];
|
|
158
|
+
if (queue) {
|
|
159
|
+
if (queue.nextTimer) {
|
|
160
|
+
clearTimeout(queue.nextTimer);
|
|
161
|
+
queue.nextTimer = null;
|
|
162
|
+
}
|
|
163
|
+
queue.queue = [];
|
|
164
|
+
queue.requestTimestamps = [];
|
|
165
|
+
queue.running = 0;
|
|
166
|
+
}
|
|
167
|
+
} else Object.keys(queues).forEach((key) => {
|
|
168
|
+
if (key.startsWith(`${clientId}:`)) {
|
|
169
|
+
const queue = queues[key];
|
|
170
|
+
if (queue?.nextTimer) {
|
|
171
|
+
clearTimeout(queue.nextTimer);
|
|
172
|
+
queue.nextTimer = null;
|
|
173
|
+
}
|
|
174
|
+
delete queues[key];
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Very naive path-based category detection. If no matcher fits, the `default` category
|
|
180
|
+
* (effectively unlimited) is returned. Adjust these heuristics as your API surface evolves.
|
|
181
|
+
*/
|
|
182
|
+
function categorizeRequest(path, method = "GET") {
|
|
183
|
+
const cleanPath = path.toLowerCase();
|
|
184
|
+
const isPost = method?.toUpperCase() === "POST";
|
|
185
|
+
if (cleanPath.includes("/documentsubmissions")) return isPost ? "submitDocuments" : "getSubmission";
|
|
186
|
+
if (cleanPath.includes("/documents/recent")) return "getRecentDocuments";
|
|
187
|
+
if (cleanPath.includes("/documents/search")) return "searchDocuments";
|
|
188
|
+
if (cleanPath.includes("/documents/state/") && cleanPath.endsWith("/state")) return "cancelDocument";
|
|
189
|
+
if (/\/documents\/[^/]+\/raw$/.test(cleanPath)) return "getDocument";
|
|
190
|
+
if (/\/documents\/[^/]+\/details$/.test(cleanPath)) return "getDocumentDetails";
|
|
191
|
+
if (cleanPath.includes("/taxpayer/search/tin")) return "searchTin";
|
|
192
|
+
if (cleanPath.includes("/taxpayer/validate/")) return "searchTin";
|
|
193
|
+
if (cleanPath.includes("/taxpayer/qrcode")) return "taxpayerQr";
|
|
194
|
+
if (cleanPath.includes("/searchtin")) return "searchTin";
|
|
195
|
+
if (cleanPath.includes("/qrcode")) return "taxpayerQr";
|
|
196
|
+
if (cleanPath.includes("/connect/token")) return "loginTaxpayer";
|
|
197
|
+
return "default";
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
//#endregion
|
|
201
|
+
export { categorizeRequest, clearQueue, queueRequest };
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/apiQueue.ts
|
|
3
|
+
const queues = {};
|
|
4
|
+
const LIMITS = {
|
|
5
|
+
loginTaxpayer: {
|
|
6
|
+
max: 12,
|
|
7
|
+
perMs: 6e4
|
|
8
|
+
},
|
|
9
|
+
loginIntermediary: {
|
|
10
|
+
max: 12,
|
|
11
|
+
perMs: 6e4
|
|
12
|
+
},
|
|
13
|
+
submitDocuments: {
|
|
14
|
+
max: 100,
|
|
15
|
+
perMs: 6e4
|
|
16
|
+
},
|
|
17
|
+
getSubmission: {
|
|
18
|
+
max: 300,
|
|
19
|
+
perMs: 6e4
|
|
20
|
+
},
|
|
21
|
+
cancelDocument: {
|
|
22
|
+
max: 12,
|
|
23
|
+
perMs: 6e4
|
|
24
|
+
},
|
|
25
|
+
rejectDocument: {
|
|
26
|
+
max: 12,
|
|
27
|
+
perMs: 6e4
|
|
28
|
+
},
|
|
29
|
+
getDocument: {
|
|
30
|
+
max: 60,
|
|
31
|
+
perMs: 6e4
|
|
32
|
+
},
|
|
33
|
+
getDocumentDetails: {
|
|
34
|
+
max: 125,
|
|
35
|
+
perMs: 6e4
|
|
36
|
+
},
|
|
37
|
+
getRecentDocuments: {
|
|
38
|
+
max: 12,
|
|
39
|
+
perMs: 6e4
|
|
40
|
+
},
|
|
41
|
+
searchDocuments: {
|
|
42
|
+
max: 12,
|
|
43
|
+
perMs: 6e4
|
|
44
|
+
},
|
|
45
|
+
searchTin: {
|
|
46
|
+
max: 60,
|
|
47
|
+
perMs: 6e4
|
|
48
|
+
},
|
|
49
|
+
taxpayerQr: {
|
|
50
|
+
max: 60,
|
|
51
|
+
perMs: 6e4
|
|
52
|
+
},
|
|
53
|
+
default: {
|
|
54
|
+
max: 12,
|
|
55
|
+
perMs: 6e4
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Clean up old timestamps outside the sliding window
|
|
60
|
+
*/
|
|
61
|
+
function cleanupTimestamps(timestamps, windowMs, now) {
|
|
62
|
+
return timestamps.filter((ts) => now - ts < windowMs);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Calculate when we can make the next request without exceeding the rate limit
|
|
66
|
+
*/
|
|
67
|
+
function getNextAvailableTime(timestamps, max, windowMs, now) {
|
|
68
|
+
if (timestamps.length < max) return now;
|
|
69
|
+
const oldestTimestamp = timestamps[0];
|
|
70
|
+
if (!oldestTimestamp) return now;
|
|
71
|
+
return oldestTimestamp + windowMs;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Public helper to schedule a request according to the category's limits.
|
|
75
|
+
* Rate limits are enforced per clientId, so multiple instances with the same
|
|
76
|
+
* clientId will share rate limiters, while different clientIds get separate limiters.
|
|
77
|
+
*
|
|
78
|
+
* This implementation uses a sliding window to track all requests within the time window.
|
|
79
|
+
*/
|
|
80
|
+
function queueRequest(clientId, category, task, debug = false) {
|
|
81
|
+
const key = `${clientId}:${category}`;
|
|
82
|
+
if (!queues[key]) queues[key] = {
|
|
83
|
+
running: 0,
|
|
84
|
+
queue: [],
|
|
85
|
+
requestTimestamps: [],
|
|
86
|
+
nextTimer: null
|
|
87
|
+
};
|
|
88
|
+
const queue = queues[key];
|
|
89
|
+
const { max, perMs } = LIMITS[category] ?? LIMITS.default;
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
const run = () => {
|
|
92
|
+
const now$1 = Date.now();
|
|
93
|
+
queue.requestTimestamps = cleanupTimestamps(queue.requestTimestamps, perMs, now$1);
|
|
94
|
+
if (queue.requestTimestamps.length >= max) {
|
|
95
|
+
const nextAvailable = getNextAvailableTime(queue.requestTimestamps, max, perMs, now$1);
|
|
96
|
+
const waitTime = nextAvailable - now$1;
|
|
97
|
+
if (debug) console.log(`[apiQueue] 🚫 Rate limit reached (${queue.requestTimestamps.length}/${max} in last ${perMs}ms). Queuing request. Need to wait ${waitTime.toFixed(0)}ms. Queue size: ${queue.queue.length + 1}`);
|
|
98
|
+
queue.queue.push({
|
|
99
|
+
run,
|
|
100
|
+
addedAt: now$1
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
queue.requestTimestamps.push(now$1);
|
|
105
|
+
queue.running++;
|
|
106
|
+
if (debug) console.log(`[apiQueue] ▶️ Executing request (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Running: ${queue.running}. Queue size: ${queue.queue.length}`);
|
|
107
|
+
task().then(resolve).catch(reject).finally(() => {
|
|
108
|
+
queue.running--;
|
|
109
|
+
if (debug) console.log(`[apiQueue] ✅ Request completed (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Running: ${queue.running}. Queue size: ${queue.queue.length}`);
|
|
110
|
+
processQueue(key, debug, category);
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
queue.requestTimestamps = cleanupTimestamps(queue.requestTimestamps, perMs, now);
|
|
115
|
+
if (queue.queue.length > 0 || queue.requestTimestamps.length >= max) {
|
|
116
|
+
queue.queue.push({
|
|
117
|
+
run,
|
|
118
|
+
addedAt: now
|
|
119
|
+
});
|
|
120
|
+
if (debug) console.log(`[apiQueue] ⏳ Queued request (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Queue size: ${queue.queue.length}`);
|
|
121
|
+
processQueue(key, debug, category);
|
|
122
|
+
} else run();
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function processQueue(key, debug, category) {
|
|
126
|
+
const queue = queues[key];
|
|
127
|
+
if (!queue || queue.queue.length === 0) return;
|
|
128
|
+
const { max, perMs } = LIMITS[category] ?? LIMITS.default;
|
|
129
|
+
const now = Date.now();
|
|
130
|
+
queue.requestTimestamps = cleanupTimestamps(queue.requestTimestamps, perMs, now);
|
|
131
|
+
if (queue.requestTimestamps.length < max) {
|
|
132
|
+
const next = queue.queue.shift();
|
|
133
|
+
if (next) {
|
|
134
|
+
if (debug) {
|
|
135
|
+
const waitTime = Date.now() - next.addedAt;
|
|
136
|
+
console.log(`[apiQueue] 🚀 Processing queued request (${category}). Waited: ${waitTime.toFixed(0)}ms. Queue size: ${queue.queue.length}`);
|
|
137
|
+
}
|
|
138
|
+
next.run();
|
|
139
|
+
}
|
|
140
|
+
if (queue.queue.length > 0) processQueue(key, debug, category);
|
|
141
|
+
} else {
|
|
142
|
+
const nextAvailable = getNextAvailableTime(queue.requestTimestamps, max, perMs, now);
|
|
143
|
+
const delay = Math.max(0, nextAvailable - now + 50);
|
|
144
|
+
if (debug) console.log(`[apiQueue] ⏸️ Delaying queue processing (${category}). Will retry in ${delay.toFixed(0)}ms. Queue size: ${queue.queue.length}`);
|
|
145
|
+
if (!queue.nextTimer) queue.nextTimer = setTimeout(() => {
|
|
146
|
+
queue.nextTimer = null;
|
|
147
|
+
processQueue(key, debug, category);
|
|
148
|
+
}, delay);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Cleanup function to clear all queues and timers for a specific client.
|
|
153
|
+
* Useful for testing or cleanup on application shutdown.
|
|
154
|
+
*/
|
|
155
|
+
function clearQueue(clientId, category) {
|
|
156
|
+
if (category) {
|
|
157
|
+
const key = `${clientId}:${category}`;
|
|
158
|
+
const queue = queues[key];
|
|
159
|
+
if (queue) {
|
|
160
|
+
if (queue.nextTimer) {
|
|
161
|
+
clearTimeout(queue.nextTimer);
|
|
162
|
+
queue.nextTimer = null;
|
|
163
|
+
}
|
|
164
|
+
queue.queue = [];
|
|
165
|
+
queue.requestTimestamps = [];
|
|
166
|
+
queue.running = 0;
|
|
167
|
+
}
|
|
168
|
+
} else Object.keys(queues).forEach((key) => {
|
|
169
|
+
if (key.startsWith(`${clientId}:`)) {
|
|
170
|
+
const queue = queues[key];
|
|
171
|
+
if (queue?.nextTimer) {
|
|
172
|
+
clearTimeout(queue.nextTimer);
|
|
173
|
+
queue.nextTimer = null;
|
|
174
|
+
}
|
|
175
|
+
delete queues[key];
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Very naive path-based category detection. If no matcher fits, the `default` category
|
|
181
|
+
* (effectively unlimited) is returned. Adjust these heuristics as your API surface evolves.
|
|
182
|
+
*/
|
|
183
|
+
function categorizeRequest(path, method = "GET") {
|
|
184
|
+
const cleanPath = path.toLowerCase();
|
|
185
|
+
const isPost = method?.toUpperCase() === "POST";
|
|
186
|
+
if (cleanPath.includes("/documentsubmissions")) return isPost ? "submitDocuments" : "getSubmission";
|
|
187
|
+
if (cleanPath.includes("/documents/recent")) return "getRecentDocuments";
|
|
188
|
+
if (cleanPath.includes("/documents/search")) return "searchDocuments";
|
|
189
|
+
if (cleanPath.includes("/documents/state/") && cleanPath.endsWith("/state")) return "cancelDocument";
|
|
190
|
+
if (/\/documents\/[^/]+\/raw$/.test(cleanPath)) return "getDocument";
|
|
191
|
+
if (/\/documents\/[^/]+\/details$/.test(cleanPath)) return "getDocumentDetails";
|
|
192
|
+
if (cleanPath.includes("/taxpayer/search/tin")) return "searchTin";
|
|
193
|
+
if (cleanPath.includes("/taxpayer/validate/")) return "searchTin";
|
|
194
|
+
if (cleanPath.includes("/taxpayer/qrcode")) return "taxpayerQr";
|
|
195
|
+
if (cleanPath.includes("/searchtin")) return "searchTin";
|
|
196
|
+
if (cleanPath.includes("/qrcode")) return "taxpayerQr";
|
|
197
|
+
if (cleanPath.includes("/connect/token")) return "loginTaxpayer";
|
|
198
|
+
return "default";
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
//#endregion
|
|
202
|
+
Object.defineProperty(exports, 'categorizeRequest', {
|
|
203
|
+
enumerable: true,
|
|
204
|
+
get: function () {
|
|
205
|
+
return categorizeRequest;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
Object.defineProperty(exports, 'clearQueue', {
|
|
209
|
+
enumerable: true,
|
|
210
|
+
get: function () {
|
|
211
|
+
return clearQueue;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
Object.defineProperty(exports, 'queueRequest', {
|
|
215
|
+
enumerable: true,
|
|
216
|
+
get: function () {
|
|
217
|
+
return queueRequest;
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
//# sourceMappingURL=apiQueue-DgKWaQDS.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiQueue-DgKWaQDS.cjs","names":["queues: Record<string, Queue>","LIMITS: Record<ApiCategory, { max: number; perMs: number }>","timestamps: number[]","windowMs: number","now: number","max: number","clientId: string","category: ApiCategory","task: Task<T>","now","key: string","debug: boolean","category?: ApiCategory","path: string","method: string"],"sources":["../src/utils/apiQueue.ts"],"sourcesContent":["// A very small utility that provides per-endpoint request queuing with rate-limits.\n// The goal is to make sure that we never exceed the vendor-defined limits while also ensuring\n// that every request is eventually executed.\n//\n// NOTE: This is intentionally minimal – no external dependencies are introduced.\n// If you need more advanced features (persistence, jitter, etc.) consider a library such as `bottleneck`.\n\n/*\nRate-limit specification (per 60-second window)\n----------------------------------------------\nLogin as Taxpayer System : 12\nLogin as Intermediary System : 12\nSubmit Documents : 100\nGet Submission : 300\nCancel Document : 12\nReject Document : 12\nGet Document : 60\nGet Document Details : 125\nGet Recent Documents : 12\nSearch Documents : 12\nSearch Taxpayer's TIN : 60\nTaxpayer's QR Code : 60\n*/\n\nexport type ApiCategory =\n | 'loginTaxpayer'\n | 'loginIntermediary'\n | 'submitDocuments'\n | 'getSubmission'\n | 'cancelDocument'\n | 'rejectDocument'\n | 'getDocument'\n | 'getDocumentDetails'\n | 'getRecentDocuments'\n | 'searchDocuments'\n | 'searchTin'\n | 'taxpayerQr'\n | 'default'\n\ntype Task<T> = () => Promise<T>\n\ninterface Queue {\n running: number\n queue: Array<{ run: () => void; addedAt: number }>\n requestTimestamps: number[] // Track all request timestamps in the sliding window\n nextTimer: NodeJS.Timeout | null // Track scheduled timer to avoid pile-up\n}\n\nconst queues: Record<string, Queue> = {}\n\n// Rate limits: max requests per time window (in ms)\nconst LIMITS: Record<ApiCategory, { max: number; perMs: number }> = {\n loginTaxpayer: { max: 12, perMs: 60000 }, // 12 req/60s\n loginIntermediary: { max: 12, perMs: 60000 }, // 12 req/60s\n submitDocuments: { max: 100, perMs: 60000 }, // 100 req/60s\n getSubmission: { max: 300, perMs: 60000 }, // 300 req/60s\n cancelDocument: { max: 12, perMs: 60000 }, // 12 req/60s\n rejectDocument: { max: 12, perMs: 60000 }, // 12 req/60s\n getDocument: { max: 60, perMs: 60000 }, // 60 req/60s\n getDocumentDetails: { max: 125, perMs: 60000 }, // 125 req/60s\n getRecentDocuments: { max: 12, perMs: 60000 }, // 12 req/60s\n searchDocuments: { max: 12, perMs: 60000 }, // 12 req/60s\n searchTin: { max: 60, perMs: 60000 }, // 60 req/60s\n taxpayerQr: { max: 60, perMs: 60000 }, // 60 req/60s\n default: { max: 12, perMs: 60000 }, // 12 req/60s (minimum limit)\n}\n\n/**\n * Clean up old timestamps outside the sliding window\n */\nfunction cleanupTimestamps(\n timestamps: number[],\n windowMs: number,\n now: number,\n): number[] {\n return timestamps.filter(ts => now - ts < windowMs)\n}\n\n/**\n * Calculate when we can make the next request without exceeding the rate limit\n */\nfunction getNextAvailableTime(\n timestamps: number[],\n max: number,\n windowMs: number,\n now: number,\n): number {\n if (timestamps.length < max) {\n return now // Can execute immediately\n }\n\n // We're at the limit. Find when the oldest request will expire\n const oldestTimestamp = timestamps[0]\n if (!oldestTimestamp) {\n return now // Shouldn't happen, but fallback to now\n }\n return oldestTimestamp + windowMs\n}\n\n/**\n * Public helper to schedule a request according to the category's limits.\n * Rate limits are enforced per clientId, so multiple instances with the same\n * clientId will share rate limiters, while different clientIds get separate limiters.\n *\n * This implementation uses a sliding window to track all requests within the time window.\n */\nexport function queueRequest<T>(\n clientId: string,\n category: ApiCategory,\n task: Task<T>,\n debug = false,\n): Promise<T> {\n const key = `${clientId}:${category}`\n if (!queues[key]) {\n queues[key] = {\n running: 0,\n queue: [],\n requestTimestamps: [],\n nextTimer: null,\n }\n }\n\n const queue = queues[key]!\n const { max, perMs } = LIMITS[category] ?? LIMITS.default\n\n return new Promise<T>((resolve, reject) => {\n const run = () => {\n const now = Date.now()\n\n // Clean up old timestamps before checking\n queue.requestTimestamps = cleanupTimestamps(\n queue.requestTimestamps,\n perMs,\n now,\n )\n\n // Check if we can execute now\n if (queue.requestTimestamps.length >= max) {\n // We've hit the rate limit, need to wait\n const nextAvailable = getNextAvailableTime(\n queue.requestTimestamps,\n max,\n perMs,\n now,\n )\n const waitTime = nextAvailable - now\n\n if (debug) {\n console.log(\n `[apiQueue] 🚫 Rate limit reached (${queue.requestTimestamps.length}/${max} in last ${perMs}ms). Queuing request. Need to wait ${waitTime.toFixed(0)}ms. Queue size: ${queue.queue.length + 1}`,\n )\n }\n\n // Re-queue this request to try again later\n queue.queue.push({ run, addedAt: now })\n // Don't call processQueue here - let the scheduled timer handle it\n // to avoid potential requeue loops\n return\n }\n\n // Record this request timestamp\n queue.requestTimestamps.push(now)\n queue.running++\n\n if (debug) {\n console.log(\n `[apiQueue] ▶️ Executing request (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Running: ${queue.running}. Queue size: ${queue.queue.length}`,\n )\n }\n\n task()\n .then(resolve)\n .catch(reject)\n .finally(() => {\n queue.running--\n if (debug) {\n console.log(\n `[apiQueue] ✅ Request completed (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Running: ${queue.running}. Queue size: ${queue.queue.length}`,\n )\n }\n processQueue(key, debug, category)\n })\n }\n\n // Add to queue or run immediately\n const now = Date.now()\n queue.requestTimestamps = cleanupTimestamps(\n queue.requestTimestamps,\n perMs,\n now,\n )\n\n if (queue.queue.length > 0 || queue.requestTimestamps.length >= max) {\n // Either there's already a queue, or we're at the rate limit\n queue.queue.push({ run, addedAt: now })\n if (debug) {\n console.log(\n `[apiQueue] ⏳ Queued request (${category}). Requests in window: ${queue.requestTimestamps.length}/${max}. Queue size: ${queue.queue.length}`,\n )\n }\n processQueue(key, debug, category)\n } else {\n // Can run immediately\n run()\n }\n })\n}\n\nfunction processQueue(key: string, debug: boolean, category: ApiCategory) {\n const queue = queues[key]\n if (!queue || queue.queue.length === 0) return\n\n const { max, perMs } = LIMITS[category] ?? LIMITS.default\n const now = Date.now()\n\n // Clean up old timestamps\n queue.requestTimestamps = cleanupTimestamps(\n queue.requestTimestamps,\n perMs,\n now,\n )\n\n // Check if we can process the next request\n if (queue.requestTimestamps.length < max) {\n // We have capacity, process immediately\n const next = queue.queue.shift()\n if (next) {\n if (debug) {\n const waitTime = Date.now() - next.addedAt\n console.log(\n `[apiQueue] 🚀 Processing queued request (${category}). Waited: ${waitTime.toFixed(0)}ms. Queue size: ${queue.queue.length}`,\n )\n }\n next.run()\n }\n // After one runs, immediately try again (in case there's more space)\n if (queue.queue.length > 0) {\n processQueue(key, debug, category)\n }\n } else {\n // We're at capacity, schedule for when the oldest request expires\n const nextAvailable = getNextAvailableTime(\n queue.requestTimestamps,\n max,\n perMs,\n now,\n )\n const delay = Math.max(0, nextAvailable - now + 50) // +50ms buffer for timer precision\n\n if (debug) {\n console.log(\n `[apiQueue] ⏸️ Delaying queue processing (${category}). Will retry in ${delay.toFixed(0)}ms. Queue size: ${queue.queue.length}`,\n )\n }\n\n // Only schedule a timer if one isn't already scheduled\n // This prevents timer pile-up during bursts\n if (!queue.nextTimer) {\n queue.nextTimer = setTimeout(() => {\n queue.nextTimer = null\n processQueue(key, debug, category)\n }, delay)\n }\n }\n}\n\n/**\n * Cleanup function to clear all queues and timers for a specific client.\n * Useful for testing or cleanup on application shutdown.\n */\nexport function clearQueue(clientId: string, category?: ApiCategory): void {\n if (category) {\n const key = `${clientId}:${category}`\n const queue = queues[key]\n if (queue) {\n if (queue.nextTimer) {\n clearTimeout(queue.nextTimer)\n queue.nextTimer = null\n }\n queue.queue = []\n queue.requestTimestamps = []\n queue.running = 0\n }\n } else {\n // Clear all queues for this client\n Object.keys(queues).forEach(key => {\n if (key.startsWith(`${clientId}:`)) {\n const queue = queues[key]\n if (queue?.nextTimer) {\n clearTimeout(queue.nextTimer)\n queue.nextTimer = null\n }\n delete queues[key]\n }\n })\n }\n}\n\n/**\n * Very naive path-based category detection. If no matcher fits, the `default` category\n * (effectively unlimited) is returned. Adjust these heuristics as your API surface evolves.\n */\nexport function categorizeRequest(\n path: string,\n method: string = 'GET',\n): ApiCategory {\n const cleanPath = path.toLowerCase()\n const isPost = method?.toUpperCase() === 'POST'\n\n if (cleanPath.includes('/documentsubmissions')) {\n return isPost ? 'submitDocuments' : 'getSubmission'\n }\n\n // -----------------------------\n // v1.0 API endpoint matchers\n // -----------------------------\n\n // Get Recent Documents - /api/v1.0/documents/recent\n if (cleanPath.includes('/documents/recent')) {\n return 'getRecentDocuments'\n }\n\n // Search Documents - /api/v1.0/documents/search\n if (cleanPath.includes('/documents/search')) {\n return 'searchDocuments'\n }\n\n // Document state actions (cancel/reject) - PUT /api/v1.0/documents/state/{uuid}/state\n // Both cancel and reject use the same endpoint, differentiated only by request body\n if (cleanPath.includes('/documents/state/') && cleanPath.endsWith('/state')) {\n // Both cancelDocument and rejectDocument share the same rate limit (12 RPM)\n // Use cancelDocument category for both since they share the same bucket\n return 'cancelDocument'\n }\n\n // Document raw content - /api/v1.0/documents/{uuid}/raw\n if (/\\/documents\\/[^/]+\\/raw$/.test(cleanPath)) {\n return 'getDocument'\n }\n\n // Document details - /api/v1.0/documents/{uuid}/details\n if (/\\/documents\\/[^/]+\\/details$/.test(cleanPath)) {\n return 'getDocumentDetails'\n }\n\n // Taxpayer TIN search & validation share same limit bucket\n if (cleanPath.includes('/taxpayer/search/tin')) return 'searchTin'\n if (cleanPath.includes('/taxpayer/validate/')) return 'searchTin'\n\n // Taxpayer QR code info\n if (cleanPath.includes('/taxpayer/qrcode')) return 'taxpayerQr'\n\n // Legacy matchers (kept for backward compatibility)\n if (cleanPath.includes('/searchtin')) return 'searchTin'\n if (cleanPath.includes('/qrcode')) return 'taxpayerQr'\n if (cleanPath.includes('/connect/token')) {\n return 'loginTaxpayer'\n }\n\n return 'default'\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -8,7 +8,7 @@ const require_platformLogin = require('./platformLogin-Ch6hFKoU.cjs');
|
|
|
8
8
|
const require_taxpayerValidation = require('./taxpayerValidation-D_jGaVty.cjs');
|
|
9
9
|
const require_certificate = require('./certificate-CWmfCPdt.cjs');
|
|
10
10
|
const require_getBaseUrl = require('./getBaseUrl-D0G4GZmp.cjs');
|
|
11
|
-
const require_apiQueue = require('./apiQueue-
|
|
11
|
+
const require_apiQueue = require('./apiQueue-DgKWaQDS.cjs');
|
|
12
12
|
|
|
13
13
|
//#region src/index.ts
|
|
14
14
|
var MyInvoisClient = class MyInvoisClient {
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { platformLogin } from "./platformLogin-CqI9OLYP.js";
|
|
|
8
8
|
import { taxpayerQRCode, tinSearch, verifyTin } from "./taxpayerValidation-y6P-Es0S.js";
|
|
9
9
|
import { extractCertificateInfo, getPemFromP12, validateKeyPair } from "./certificate-COwqszxD.js";
|
|
10
10
|
import { getBaseUrl } from "./getBaseUrl-D7nUmoYb.js";
|
|
11
|
-
import { categorizeRequest, queueRequest } from "./apiQueue-
|
|
11
|
+
import { categorizeRequest, queueRequest } from "./apiQueue-B6Q644Bz.js";
|
|
12
12
|
|
|
13
13
|
//#region src/index.ts
|
|
14
14
|
var MyInvoisClient = class MyInvoisClient {
|
package/dist/index10.cjs
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
|
-
const require_certificate = require('./certificate-CWmfCPdt.cjs');
|
|
2
1
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
//#region src/types/payment-modes.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Enum representing the allowed payment mode codes with descriptive names.
|
|
5
|
+
* Provides a more readable way to reference payment modes.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const mode = PaymentModeCodeEnum.Cash;
|
|
9
|
+
* console.log(mode); // Output: "01"
|
|
10
|
+
*/
|
|
11
|
+
let PaymentModeCodeEnum = /* @__PURE__ */ function(PaymentModeCodeEnum$1) {
|
|
12
|
+
PaymentModeCodeEnum$1["Cash"] = "01";
|
|
13
|
+
PaymentModeCodeEnum$1["Cheque"] = "02";
|
|
14
|
+
PaymentModeCodeEnum$1["BankTransfer"] = "03";
|
|
15
|
+
PaymentModeCodeEnum$1["CreditCard"] = "04";
|
|
16
|
+
PaymentModeCodeEnum$1["DebitCard"] = "05";
|
|
17
|
+
PaymentModeCodeEnum$1["EWalletDigitalWallet"] = "06";
|
|
18
|
+
PaymentModeCodeEnum$1["DigitalBank"] = "07";
|
|
19
|
+
PaymentModeCodeEnum$1["Others"] = "08";
|
|
20
|
+
return PaymentModeCodeEnum$1;
|
|
21
|
+
}({});
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
exports.PaymentModeCodeEnum = PaymentModeCodeEnum;
|
|
25
|
+
//# sourceMappingURL=index10.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index10.cjs","names":[],"sources":["../src/types/payment-modes.d.ts"],"sourcesContent":["/**\n * Represents the allowed codes for payment modes.\n * Based on the documentation: https://sdk.myinvois.hasil.gov.my/codes/payment-methods/\n */\nexport type PaymentModeCode =\n | '01' // Cash\n | '02' // Cheque\n | '03' // Bank Transfer\n | '04' // Credit Card\n | '05' // Debit Card\n | '06' // e-Wallet / Digital Wallet\n | '07' // Digital Bank\n | '08' // Others\n\n/**\n * Enum representing the allowed payment mode codes with descriptive names.\n * Provides a more readable way to reference payment modes.\n *\n * @example\n * const mode = PaymentModeCodeEnum.Cash;\n * console.log(mode); // Output: \"01\"\n */\nexport enum PaymentModeCodeEnum {\n Cash = '01',\n Cheque = '02',\n BankTransfer = '03',\n CreditCard = '04',\n DebitCard = '05',\n EWalletDigitalWallet = '06',\n DigitalBank = '07',\n Others = '08',\n}\n\n/**\n * Interface representing a payment mode entry.\n * Contains the code and its corresponding description.\n */\nexport interface PaymentMode {\n code: PaymentModeCode\n description: string\n}\n"],"mappings":";;;;;;;;;;AAsBA,IAAY,sEAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACD"}
|
package/dist/index11.cjs
CHANGED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
require('./formatIdValue-i67o4kyD.cjs');
|
|
2
|
-
const require_document = require('./document-CCza2JPL.cjs');
|
|
3
|
-
|
|
4
|
-
exports.calculateCertificateDigest = require_document.calculateCertificateDigest;
|
|
5
|
-
exports.calculateDocumentDigest = require_document.calculateDocumentDigest;
|
|
6
|
-
exports.calculateExpectedTaxAmount = require_document.calculateExpectedTaxAmount;
|
|
7
|
-
exports.calculateInvoiceTotals = require_document.calculateInvoiceTotals;
|
|
8
|
-
exports.calculateSignedPropertiesDigest = require_document.calculateSignedPropertiesDigest;
|
|
9
|
-
exports.canonicalizeJSON = require_document.canonicalizeJSON;
|
|
10
|
-
exports.createFixedRateTaxLineItem = require_document.createFixedRateTaxLineItem;
|
|
11
|
-
exports.createPercentageTaxLineItem = require_document.createPercentageTaxLineItem;
|
|
12
|
-
exports.createSignedInfoAndSign = require_document.createSignedInfoAndSign;
|
|
13
|
-
exports.createSignedProperties = require_document.createSignedProperties;
|
|
14
|
-
exports.extractCertificateInfo = require_document.extractCertificateInfo;
|
|
15
|
-
exports.generateCleanInvoiceObject = require_document.generateCleanInvoiceObject;
|
|
16
|
-
exports.generateCleanUBLDocument = require_document.generateCleanUBLDocument;
|
|
17
|
-
exports.generateCompleteDocument = require_document.generateCompleteDocument;
|
|
18
|
-
exports.isFixedRateTax = require_document.isFixedRateTax;
|
|
19
|
-
exports.isPercentageTax = require_document.isPercentageTax;
|
|
20
|
-
exports.signDocumentString = require_document.signDocumentString;
|
|
21
|
-
exports.sortObjectKeys = require_document.sortObjectKeys;
|
|
22
|
-
exports.transformDocumentForHashing = require_document.transformDocumentForHashing;
|
package/dist/index12.cjs
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
-
const require_formatIdValue = require('./formatIdValue-i67o4kyD.cjs');
|
|
2
1
|
|
|
3
|
-
|
|
2
|
+
//#region src/types/state-codes.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Enum representing the allowed state codes with descriptive names.
|
|
5
|
+
* Provides a more readable way to reference states.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const code = StateCodeEnum.Selangor;
|
|
9
|
+
* console.log(code); // Output: "10"
|
|
10
|
+
*/
|
|
11
|
+
let StateCodeEnum = /* @__PURE__ */ function(StateCodeEnum$1) {
|
|
12
|
+
StateCodeEnum$1["Johor"] = "01";
|
|
13
|
+
StateCodeEnum$1["Kedah"] = "02";
|
|
14
|
+
StateCodeEnum$1["Kelantan"] = "03";
|
|
15
|
+
StateCodeEnum$1["Melaka"] = "04";
|
|
16
|
+
StateCodeEnum$1["NegeriSembilan"] = "05";
|
|
17
|
+
StateCodeEnum$1["Pahang"] = "06";
|
|
18
|
+
StateCodeEnum$1["PulauPinang"] = "07";
|
|
19
|
+
StateCodeEnum$1["Perak"] = "08";
|
|
20
|
+
StateCodeEnum$1["Perlis"] = "09";
|
|
21
|
+
StateCodeEnum$1["Selangor"] = "10";
|
|
22
|
+
StateCodeEnum$1["Terengganu"] = "11";
|
|
23
|
+
StateCodeEnum$1["Sabah"] = "12";
|
|
24
|
+
StateCodeEnum$1["Sarawak"] = "13";
|
|
25
|
+
StateCodeEnum$1["WPKualaLumpur"] = "14";
|
|
26
|
+
StateCodeEnum$1["WPLabuan"] = "15";
|
|
27
|
+
StateCodeEnum$1["WPPutrajaya"] = "16";
|
|
28
|
+
StateCodeEnum$1["NotApplicable"] = "17";
|
|
29
|
+
return StateCodeEnum$1;
|
|
30
|
+
}({});
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
exports.StateCodeEnum = StateCodeEnum;
|
|
34
|
+
//# sourceMappingURL=index12.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index12.cjs","names":[],"sources":["../src/types/state-codes.d.ts"],"sourcesContent":["/**\n * Represents the allowed codes for Malaysian states and federal territories.\n * Based on the documentation: https://sdk.myinvois.hasil.gov.my/codes/state-codes/\n */\nexport type StateCode =\n | '01' // Johor\n | '02' // Kedah\n | '03' // Kelantan\n | '04' // Melaka\n | '05' // Negeri Sembilan\n | '06' // Pahang\n | '07' // Pulau Pinang\n | '08' // Perak\n | '09' // Perlis\n | '10' // Selangor\n | '11' // Terengganu\n | '12' // Sabah\n | '13' // Sarawak\n | '14' // Wilayah Persekutuan Kuala Lumpur\n | '15' // Wilayah Persekutuan Labuan\n | '16' // Wilayah Persekutuan Putrajaya\n | '17' // Not Applicable\n\n/**\n * Enum representing the allowed state codes with descriptive names.\n * Provides a more readable way to reference states.\n *\n * @example\n * const code = StateCodeEnum.Selangor;\n * console.log(code); // Output: \"10\"\n */\nexport enum StateCodeEnum {\n Johor = '01',\n Kedah = '02',\n Kelantan = '03',\n Melaka = '04',\n NegeriSembilan = '05',\n Pahang = '06',\n PulauPinang = '07',\n Perak = '08',\n Perlis = '09',\n Selangor = '10',\n Terengganu = '11',\n Sabah = '12',\n Sarawak = '13',\n WPKualaLumpur = '14',\n WPLabuan = '15',\n WPPutrajaya = '16',\n NotApplicable = '17',\n}\n\n/**\n * Interface representing a state code entry.\n * Contains the code and its corresponding name.\n */\nexport interface State {\n code: StateCode\n name: string\n}\n"],"mappings":";;;;;;;;;;AA+BA,IAAY,0DAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACD"}
|
package/dist/index13.cjs
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
-
const require_getBaseUrl = require('./getBaseUrl-D0G4GZmp.cjs');
|
|
2
1
|
|
|
3
|
-
|
|
2
|
+
//#region src/types/tax-types.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Enum representing the allowed tax type codes with descriptive names.
|
|
5
|
+
* Provides a more readable way to reference tax types.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const code = TaxTypeCodeEnum.SalesTax;
|
|
9
|
+
* console.log(code); // Output: "01"
|
|
10
|
+
*/
|
|
11
|
+
let TaxTypeCodeEnum = /* @__PURE__ */ function(TaxTypeCodeEnum$1) {
|
|
12
|
+
TaxTypeCodeEnum$1["SalesTax"] = "01";
|
|
13
|
+
TaxTypeCodeEnum$1["ServiceTax"] = "02";
|
|
14
|
+
TaxTypeCodeEnum$1["TourismTax"] = "03";
|
|
15
|
+
TaxTypeCodeEnum$1["HighValueGoodsTax"] = "04";
|
|
16
|
+
TaxTypeCodeEnum$1["SalesTaxLowValueGoods"] = "05";
|
|
17
|
+
TaxTypeCodeEnum$1["NotApplicable"] = "06";
|
|
18
|
+
TaxTypeCodeEnum$1["TaxExemption"] = "E";
|
|
19
|
+
return TaxTypeCodeEnum$1;
|
|
20
|
+
}({});
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
exports.TaxTypeCodeEnum = TaxTypeCodeEnum;
|
|
24
|
+
//# sourceMappingURL=index13.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index13.cjs","names":[],"sources":["../src/types/tax-types.d.ts"],"sourcesContent":["/**\n * Represents the allowed codes for tax types.\n * Based on the documentation: https://sdk.myinvois.hasil.gov.my/codes/tax-types/\n */\nexport type TaxTypeCode =\n | '01' // Sales Tax\n | '02' // Service Tax\n | '03' // Tourism Tax\n | '04' // High-Value Goods Tax\n | '05' // Sales Tax on Low Value Goods\n | '06' // Not Applicable\n | 'E' // Tax exemption (where applicable)\n\n/**\n * Enum representing the allowed tax type codes with descriptive names.\n * Provides a more readable way to reference tax types.\n *\n * @example\n * const code = TaxTypeCodeEnum.SalesTax;\n * console.log(code); // Output: \"01\"\n */\nexport enum TaxTypeCodeEnum {\n SalesTax = '01',\n ServiceTax = '02',\n TourismTax = '03',\n HighValueGoodsTax = '04',\n SalesTaxLowValueGoods = '05',\n NotApplicable = '06',\n TaxExemption = 'E',\n}\n\n/**\n * Interface representing a tax type entry.\n * Contains the code and its corresponding description.\n */\nexport interface TaxType {\n code: TaxTypeCode\n description: string\n}\n"],"mappings":";;;;;;;;;;AAqBA,IAAY,8DAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AACD"}
|