ebag 0.0.2
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/README.md +89 -0
- package/dist/cli/format.d.ts +12 -0
- package/dist/cli/format.js +354 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +447 -0
- package/dist/lib/auth.d.ts +3 -0
- package/dist/lib/auth.js +17 -0
- package/dist/lib/cart.d.ts +4 -0
- package/dist/lib/cart.js +46 -0
- package/dist/lib/client.d.ts +13 -0
- package/dist/lib/client.js +96 -0
- package/dist/lib/config.d.ts +11 -0
- package/dist/lib/config.js +90 -0
- package/dist/lib/cookies.d.ts +2 -0
- package/dist/lib/cookies.js +30 -0
- package/dist/lib/index.d.ts +9 -0
- package/dist/lib/index.js +25 -0
- package/dist/lib/lists.d.ts +4 -0
- package/dist/lib/lists.js +41 -0
- package/dist/lib/orders.d.ts +14 -0
- package/dist/lib/orders.js +266 -0
- package/dist/lib/products.d.ts +2 -0
- package/dist/lib/products.js +8 -0
- package/dist/lib/search.d.ts +7 -0
- package/dist/lib/search.js +181 -0
- package/dist/lib/slots.d.ts +6 -0
- package/dist/lib/slots.js +55 -0
- package/dist/lib/types.d.ts +115 -0
- package/dist/lib/types.js +2 -0
- package/package.json +53 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getConfigDir = getConfigDir;
|
|
7
|
+
exports.getConfigPath = getConfigPath;
|
|
8
|
+
exports.getSessionPath = getSessionPath;
|
|
9
|
+
exports.getCachePath = getCachePath;
|
|
10
|
+
exports.loadConfig = loadConfig;
|
|
11
|
+
exports.saveConfig = saveConfig;
|
|
12
|
+
exports.loadSession = loadSession;
|
|
13
|
+
exports.saveSession = saveSession;
|
|
14
|
+
exports.loadCache = loadCache;
|
|
15
|
+
exports.saveCache = saveCache;
|
|
16
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
17
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
18
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
19
|
+
const DEFAULT_CONFIG = {
|
|
20
|
+
baseUrl: 'https://www.ebag.bg',
|
|
21
|
+
algolia: {
|
|
22
|
+
appId: 'JMJMDQ9HHX',
|
|
23
|
+
apiKey: '42ca9458d9354298c7016ce9155d8481',
|
|
24
|
+
host: 'jmjmdq9hhx-dsn.algolia.net',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
function ensureDir(dir) {
|
|
28
|
+
node_fs_1.default.mkdirSync(dir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
function getConfigDir() {
|
|
31
|
+
const override = process.env.EBAG_CONFIG_DIR;
|
|
32
|
+
if (override) {
|
|
33
|
+
return override;
|
|
34
|
+
}
|
|
35
|
+
return node_path_1.default.join(node_os_1.default.homedir(), '.config', 'ebag');
|
|
36
|
+
}
|
|
37
|
+
function readJsonFile(filePath, fallback) {
|
|
38
|
+
try {
|
|
39
|
+
const raw = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
40
|
+
return JSON.parse(raw);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return fallback;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function writeJsonFile(filePath, data) {
|
|
47
|
+
ensureDir(node_path_1.default.dirname(filePath));
|
|
48
|
+
node_fs_1.default.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
49
|
+
}
|
|
50
|
+
function writeSessionFile(filePath, data) {
|
|
51
|
+
ensureDir(node_path_1.default.dirname(filePath));
|
|
52
|
+
node_fs_1.default.writeFileSync(filePath, JSON.stringify(data, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
53
|
+
}
|
|
54
|
+
function getConfigPath() {
|
|
55
|
+
return node_path_1.default.join(getConfigDir(), 'config.json');
|
|
56
|
+
}
|
|
57
|
+
function getSessionPath() {
|
|
58
|
+
return node_path_1.default.join(getConfigDir(), 'session.json');
|
|
59
|
+
}
|
|
60
|
+
function getCachePath() {
|
|
61
|
+
return node_path_1.default.join(getConfigDir(), 'cache.json');
|
|
62
|
+
}
|
|
63
|
+
function loadConfig() {
|
|
64
|
+
const stored = readJsonFile(getConfigPath(), {});
|
|
65
|
+
const algolia = {
|
|
66
|
+
appId: stored.algolia?.appId ?? DEFAULT_CONFIG.algolia?.appId ?? 'JMJMDQ9HHX',
|
|
67
|
+
apiKey: stored.algolia?.apiKey ?? DEFAULT_CONFIG.algolia?.apiKey ?? '42ca9458d9354298c7016ce9155d8481',
|
|
68
|
+
host: stored.algolia?.host ?? DEFAULT_CONFIG.algolia?.host,
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
...DEFAULT_CONFIG,
|
|
72
|
+
...stored,
|
|
73
|
+
algolia,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function saveConfig(config) {
|
|
77
|
+
writeJsonFile(getConfigPath(), config);
|
|
78
|
+
}
|
|
79
|
+
function loadSession() {
|
|
80
|
+
return readJsonFile(getSessionPath(), {});
|
|
81
|
+
}
|
|
82
|
+
function saveSession(session) {
|
|
83
|
+
writeSessionFile(getSessionPath(), session);
|
|
84
|
+
}
|
|
85
|
+
function loadCache() {
|
|
86
|
+
return readJsonFile(getCachePath(), { products: {}, orders: {} });
|
|
87
|
+
}
|
|
88
|
+
function saveCache(cache) {
|
|
89
|
+
writeJsonFile(getCachePath(), cache);
|
|
90
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare function normalizeCookieInput(value: string): string;
|
|
2
|
+
export declare function validateCookieInput(value: string): "Cookie value is empty." | "Cookie value should be a single header line without newlines." | "Cookie value should look like \"name=value\" pairs from the Cookie header." | null;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeCookieInput = normalizeCookieInput;
|
|
4
|
+
exports.validateCookieInput = validateCookieInput;
|
|
5
|
+
function normalizeCookieInput(value) {
|
|
6
|
+
const trimmed = value.trim();
|
|
7
|
+
if (trimmed.toLowerCase().startsWith('cookie:')) {
|
|
8
|
+
return trimmed.slice('cookie:'.length).trim();
|
|
9
|
+
}
|
|
10
|
+
return trimmed;
|
|
11
|
+
}
|
|
12
|
+
function validateCookieInput(value) {
|
|
13
|
+
if (!value) {
|
|
14
|
+
return 'Cookie value is empty.';
|
|
15
|
+
}
|
|
16
|
+
if (value.includes('\n') || value.includes('\r')) {
|
|
17
|
+
return 'Cookie value should be a single header line without newlines.';
|
|
18
|
+
}
|
|
19
|
+
const parts = value.split(';').map((part) => part.trim()).filter(Boolean);
|
|
20
|
+
if (parts.length === 0) {
|
|
21
|
+
return 'Cookie value should look like "name=value" pairs from the Cookie header.';
|
|
22
|
+
}
|
|
23
|
+
for (const part of parts) {
|
|
24
|
+
const eqIndex = part.indexOf('=');
|
|
25
|
+
if (eqIndex <= 0 || eqIndex === part.length - 1) {
|
|
26
|
+
return 'Cookie value should look like "name=value" pairs from the Cookie header.';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./auth"), exports);
|
|
18
|
+
__exportStar(require("./cart"), exports);
|
|
19
|
+
__exportStar(require("./client"), exports);
|
|
20
|
+
__exportStar(require("./config"), exports);
|
|
21
|
+
__exportStar(require("./lists"), exports);
|
|
22
|
+
__exportStar(require("./orders"), exports);
|
|
23
|
+
__exportStar(require("./products"), exports);
|
|
24
|
+
__exportStar(require("./search"), exports);
|
|
25
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Config, ListSummary, Session } from './types';
|
|
2
|
+
export declare function getLists(config: Config, session: Session): Promise<ListSummary[]>;
|
|
3
|
+
export declare function addToList(config: Config, session: Session, listId: number, productId: number, quantity: number): Promise<unknown>;
|
|
4
|
+
export declare function getListItems(config: Config, session: Session, listId: number, page?: number): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLists = getLists;
|
|
4
|
+
exports.addToList = addToList;
|
|
5
|
+
exports.getListItems = getListItems;
|
|
6
|
+
const client_1 = require("./client");
|
|
7
|
+
async function getLists(config, session) {
|
|
8
|
+
const result = await (0, client_1.requestEbag)(config, session, '/lists/json');
|
|
9
|
+
return result.data.map((list) => ({
|
|
10
|
+
id: list.id,
|
|
11
|
+
name: list.name,
|
|
12
|
+
type: list.type,
|
|
13
|
+
publicId: list.public_id ?? null,
|
|
14
|
+
isReadOnly: list.is_read_only ?? list.isReadOnly,
|
|
15
|
+
products: list.products?.map((p) => ({
|
|
16
|
+
productId: p.product_id,
|
|
17
|
+
quantity: p.quantity,
|
|
18
|
+
})),
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
async function addToList(config, session, listId, productId, quantity) {
|
|
22
|
+
const baseUrl = config.baseUrl || 'https://www.ebag.bg';
|
|
23
|
+
const body = new URLSearchParams({
|
|
24
|
+
product_id: String(productId),
|
|
25
|
+
quantity: String(quantity),
|
|
26
|
+
});
|
|
27
|
+
const result = await (0, client_1.requestEbag)(config, session, `/lists/${listId}/items/update`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: {
|
|
30
|
+
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
31
|
+
origin: baseUrl,
|
|
32
|
+
referer: `${baseUrl}/search/`,
|
|
33
|
+
},
|
|
34
|
+
body,
|
|
35
|
+
});
|
|
36
|
+
return result.data;
|
|
37
|
+
}
|
|
38
|
+
async function getListItems(config, session, listId, page = 1) {
|
|
39
|
+
const result = await (0, client_1.requestEbag)(config, session, `/lists/${listId}/items/json`, { query: { page } });
|
|
40
|
+
return result.data;
|
|
41
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Config, OrderDetail, OrderSummary, Session } from './types';
|
|
2
|
+
export declare function getTimeSlots(config: Config, session: Session): Promise<Record<string, unknown>>;
|
|
3
|
+
export declare function listOrders(config: Config, session: Session, options?: {
|
|
4
|
+
limit?: number;
|
|
5
|
+
page?: number;
|
|
6
|
+
from?: string;
|
|
7
|
+
to?: string;
|
|
8
|
+
}): Promise<{
|
|
9
|
+
count: number;
|
|
10
|
+
results: OrderSummary[];
|
|
11
|
+
next: string | null;
|
|
12
|
+
previous: string | null;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function getOrderDetail(config: Config, session: Session, orderId: string): Promise<OrderDetail>;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTimeSlots = getTimeSlots;
|
|
4
|
+
exports.listOrders = listOrders;
|
|
5
|
+
exports.getOrderDetail = getOrderDetail;
|
|
6
|
+
const config_1 = require("./config");
|
|
7
|
+
const client_1 = require("./client");
|
|
8
|
+
async function getTimeSlots(config, session) {
|
|
9
|
+
const result = await (0, client_1.requestEbag)(config, session, '/orders/get-time-slots');
|
|
10
|
+
return result.data;
|
|
11
|
+
}
|
|
12
|
+
function normalizeDate(value) {
|
|
13
|
+
if (!value)
|
|
14
|
+
return undefined;
|
|
15
|
+
const isoMatch = value.match(/(\d{4})-(\d{2})-(\d{2})/);
|
|
16
|
+
if (isoMatch)
|
|
17
|
+
return `${isoMatch[1]}-${isoMatch[2]}-${isoMatch[3]}`;
|
|
18
|
+
const ymdAlt = value.match(/(\d{4})[./](\d{2})[./](\d{2})/);
|
|
19
|
+
if (ymdAlt)
|
|
20
|
+
return `${ymdAlt[1]}-${ymdAlt[2]}-${ymdAlt[3]}`;
|
|
21
|
+
const dmyMatch = value.match(/(\d{2})[./-](\d{2})[./-](\d{4})/);
|
|
22
|
+
if (dmyMatch)
|
|
23
|
+
return `${dmyMatch[3]}-${dmyMatch[2]}-${dmyMatch[1]}`;
|
|
24
|
+
const parsed = new Date(value);
|
|
25
|
+
if (Number.isNaN(parsed.getTime()))
|
|
26
|
+
return undefined;
|
|
27
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
28
|
+
return `${parsed.getFullYear()}-${pad(parsed.getMonth() + 1)}-${pad(parsed.getDate())}`;
|
|
29
|
+
}
|
|
30
|
+
function normalizeOrderSummary(entry) {
|
|
31
|
+
const parseNumber = (value) => {
|
|
32
|
+
if (typeof value === 'number')
|
|
33
|
+
return value;
|
|
34
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
35
|
+
const parsed = Number(value);
|
|
36
|
+
return Number.isNaN(parsed) ? undefined : parsed;
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
id: entry.encrypted_id ? String(entry.encrypted_id) : '',
|
|
42
|
+
shippingDate: entry.shipping_date ? String(entry.shipping_date) : undefined,
|
|
43
|
+
timeSlotStart: parseNumber(entry.time_slot_start),
|
|
44
|
+
timeSlotEnd: parseNumber(entry.time_slot_end),
|
|
45
|
+
timeSlotDisplay: entry.time_slot_display ? String(entry.time_slot_display) : undefined,
|
|
46
|
+
status: parseNumber(entry.order_status),
|
|
47
|
+
statusText: entry.order_status_pharmacy
|
|
48
|
+
? String(entry.order_status_pharmacy)
|
|
49
|
+
: entry.order_status_text
|
|
50
|
+
? String(entry.order_status_text)
|
|
51
|
+
: null,
|
|
52
|
+
finalAmount: entry.final_amount ? String(entry.final_amount) : undefined,
|
|
53
|
+
finalAmountEur: entry.final_amount_eur ? String(entry.final_amount_eur) : undefined,
|
|
54
|
+
additionalOrdersCount: typeof entry.additional_orders_count === 'number'
|
|
55
|
+
? entry.additional_orders_count
|
|
56
|
+
: entry.additional_orders_count !== undefined
|
|
57
|
+
? Number(entry.additional_orders_count)
|
|
58
|
+
: undefined,
|
|
59
|
+
phone: entry.phone ? String(entry.phone) : undefined,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function normalizeGroupedItems(groupedItems) {
|
|
63
|
+
if (!Array.isArray(groupedItems))
|
|
64
|
+
return [];
|
|
65
|
+
const items = [];
|
|
66
|
+
for (const group of groupedItems) {
|
|
67
|
+
if (!group || typeof group !== 'object')
|
|
68
|
+
continue;
|
|
69
|
+
const groupName = group.group_name;
|
|
70
|
+
const groupItems = group.group_items || [];
|
|
71
|
+
for (const entry of groupItems) {
|
|
72
|
+
if (!entry || typeof entry !== 'object')
|
|
73
|
+
continue;
|
|
74
|
+
const item = entry;
|
|
75
|
+
const product = item.product || undefined;
|
|
76
|
+
const productSaved = item.product_saved || undefined;
|
|
77
|
+
const name = product?.name ||
|
|
78
|
+
item.product_saved_name ||
|
|
79
|
+
productSaved?.name_bg ||
|
|
80
|
+
productSaved?.name_en ||
|
|
81
|
+
'Unknown';
|
|
82
|
+
const id = typeof product?.id === 'number'
|
|
83
|
+
? product.id
|
|
84
|
+
: product?.id
|
|
85
|
+
? Number(product.id)
|
|
86
|
+
: typeof productSaved?.id === 'number'
|
|
87
|
+
? productSaved.id
|
|
88
|
+
: productSaved?.id
|
|
89
|
+
? Number(productSaved.id)
|
|
90
|
+
: undefined;
|
|
91
|
+
items.push({
|
|
92
|
+
id,
|
|
93
|
+
name,
|
|
94
|
+
quantity: item.quantity ? String(item.quantity) : undefined,
|
|
95
|
+
unit: product?.unit_weight_text ? String(product.unit_weight_text) : undefined,
|
|
96
|
+
price: item.price ? String(item.price) : undefined,
|
|
97
|
+
priceEur: item.price_eur ? String(item.price_eur) : undefined,
|
|
98
|
+
regularPrice: item.regular_price ? String(item.regular_price) : undefined,
|
|
99
|
+
regularPriceEur: item.regular_price_eur ? String(item.regular_price_eur) : undefined,
|
|
100
|
+
group: groupName ? String(groupName) : undefined,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return items;
|
|
105
|
+
}
|
|
106
|
+
function normalizeOrderDetail(payload) {
|
|
107
|
+
const order = payload.order || {};
|
|
108
|
+
const parseNumber = (value) => {
|
|
109
|
+
if (typeof value === 'number')
|
|
110
|
+
return value;
|
|
111
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
112
|
+
const parsed = Number(value);
|
|
113
|
+
return Number.isNaN(parsed) ? undefined : parsed;
|
|
114
|
+
}
|
|
115
|
+
return undefined;
|
|
116
|
+
};
|
|
117
|
+
const addressSerialized = order.address_serialized ? String(order.address_serialized) : '';
|
|
118
|
+
const city = order.city ? String(order.city) : '';
|
|
119
|
+
const neighbourhood = order.neighbourhood ? String(order.neighbourhood) : '';
|
|
120
|
+
const street = order.street ? String(order.street) : '';
|
|
121
|
+
const address = addressSerialized || [city, neighbourhood, street].filter(Boolean).join(', ');
|
|
122
|
+
const additionalOrdersRaw = Array.isArray(order.additional_orders)
|
|
123
|
+
? order.additional_orders
|
|
124
|
+
: [];
|
|
125
|
+
return {
|
|
126
|
+
id: order.encrypted_id ? String(order.encrypted_id) : '',
|
|
127
|
+
status: parseNumber(order.order_status),
|
|
128
|
+
statusText: order.order_status_pharmacy
|
|
129
|
+
? String(order.order_status_pharmacy)
|
|
130
|
+
: order.order_status_text
|
|
131
|
+
? String(order.order_status_text)
|
|
132
|
+
: order.pay_button_text
|
|
133
|
+
? String(order.pay_button_text)
|
|
134
|
+
: null,
|
|
135
|
+
shippingDate: order.shipping_date ? String(order.shipping_date) : undefined,
|
|
136
|
+
timeSlotDisplay: order.timeslot_display
|
|
137
|
+
? String(order.timeslot_display)
|
|
138
|
+
: order.time_slot_display
|
|
139
|
+
? String(order.time_slot_display)
|
|
140
|
+
: undefined,
|
|
141
|
+
address: address || undefined,
|
|
142
|
+
totals: {
|
|
143
|
+
total: order.total ? String(order.total) : undefined,
|
|
144
|
+
totalEur: order.total_eur ? String(order.total_eur) : undefined,
|
|
145
|
+
totalPaid: order.total_price_paid ? String(order.total_price_paid) : undefined,
|
|
146
|
+
totalPaidEur: order.total_price_paid_eur ? String(order.total_price_paid_eur) : undefined,
|
|
147
|
+
discount: order.discount ? String(order.discount) : undefined,
|
|
148
|
+
discountEur: order.discount_eur ? String(order.discount_eur) : undefined,
|
|
149
|
+
tip: order.tip ? String(order.tip) : undefined,
|
|
150
|
+
tipEur: order.tip_eur ? String(order.tip_eur) : undefined,
|
|
151
|
+
},
|
|
152
|
+
items: normalizeGroupedItems(payload.grouped_items),
|
|
153
|
+
additionalOrders: additionalOrdersRaw.length
|
|
154
|
+
? additionalOrdersRaw.map((entry) => normalizeOrderDetail(entry))
|
|
155
|
+
: undefined,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function filterByDate(orders, from, to) {
|
|
159
|
+
if (!from && !to)
|
|
160
|
+
return orders;
|
|
161
|
+
return orders.filter((order) => {
|
|
162
|
+
const date = order.shippingDate;
|
|
163
|
+
if (!date)
|
|
164
|
+
return false;
|
|
165
|
+
if (from && date < from)
|
|
166
|
+
return false;
|
|
167
|
+
if (to && date > to)
|
|
168
|
+
return false;
|
|
169
|
+
return true;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
async function listOrders(config, session, options = {}) {
|
|
173
|
+
const limit = options.limit ?? 10;
|
|
174
|
+
const from = normalizeDate(options.from);
|
|
175
|
+
const to = normalizeDate(options.to);
|
|
176
|
+
const hasRange = Boolean(from || to);
|
|
177
|
+
const results = [];
|
|
178
|
+
let next = null;
|
|
179
|
+
let previous = null;
|
|
180
|
+
const maxPages = options.page ? 1 : hasRange ? 200 : 20;
|
|
181
|
+
const years = [];
|
|
182
|
+
if (from && to) {
|
|
183
|
+
const start = Number(from.slice(0, 4));
|
|
184
|
+
const end = Number(to.slice(0, 4));
|
|
185
|
+
for (let year = start; year <= end; year += 1)
|
|
186
|
+
years.push(year);
|
|
187
|
+
}
|
|
188
|
+
else if (from) {
|
|
189
|
+
const start = Number(from.slice(0, 4));
|
|
190
|
+
const currentYear = new Date().getFullYear();
|
|
191
|
+
for (let year = start; year <= currentYear; year += 1)
|
|
192
|
+
years.push(year);
|
|
193
|
+
}
|
|
194
|
+
else if (to) {
|
|
195
|
+
const end = Number(to.slice(0, 4));
|
|
196
|
+
const currentYear = new Date().getFullYear();
|
|
197
|
+
for (let year = end; year <= currentYear; year += 1)
|
|
198
|
+
years.push(year);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
years.push(new Date().getFullYear());
|
|
202
|
+
}
|
|
203
|
+
const fetchYears = hasRange ? years : [new Date().getFullYear()];
|
|
204
|
+
for (const year of fetchYears) {
|
|
205
|
+
let page = options.page ?? 1;
|
|
206
|
+
let pagesFetched = 0;
|
|
207
|
+
while (results.length < limit) {
|
|
208
|
+
const result = await (0, client_1.requestEbag)(config, session, '/orders/list/json', {
|
|
209
|
+
query: {
|
|
210
|
+
page,
|
|
211
|
+
year: hasRange ? year : undefined,
|
|
212
|
+
exclude_additional_order: 'true',
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
const payload = result.data;
|
|
216
|
+
next = payload.next ?? null;
|
|
217
|
+
previous = payload.previous ?? null;
|
|
218
|
+
const normalized = payload.results.map(normalizeOrderSummary);
|
|
219
|
+
const filtered = filterByDate(normalized, from, to);
|
|
220
|
+
results.push(...filtered);
|
|
221
|
+
pagesFetched += 1;
|
|
222
|
+
if (!payload.next || pagesFetched >= maxPages) {
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
if (from) {
|
|
226
|
+
const lastDate = normalized[normalized.length - 1]?.shippingDate;
|
|
227
|
+
if (lastDate && lastDate < from) {
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
page += 1;
|
|
232
|
+
}
|
|
233
|
+
if (results.length >= limit)
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
count: results.slice(0, limit).length,
|
|
238
|
+
results: results.slice(0, limit),
|
|
239
|
+
next,
|
|
240
|
+
previous,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function getCachedOrder(cache, orderId) {
|
|
244
|
+
return cache.orders?.[orderId];
|
|
245
|
+
}
|
|
246
|
+
async function getOrderDetail(config, session, orderId) {
|
|
247
|
+
const cache = (0, config_1.loadCache)();
|
|
248
|
+
const cached = getCachedOrder(cache, orderId);
|
|
249
|
+
if (cached && cached.status === 4) {
|
|
250
|
+
return cached.detail;
|
|
251
|
+
}
|
|
252
|
+
const result = await (0, client_1.requestEbag)(config, session, `/orders/${orderId}/details/json`);
|
|
253
|
+
const detail = normalizeOrderDetail(result.data);
|
|
254
|
+
if (!cache.orders) {
|
|
255
|
+
cache.orders = {};
|
|
256
|
+
}
|
|
257
|
+
if (detail.status === 4) {
|
|
258
|
+
cache.orders[orderId] = {
|
|
259
|
+
status: detail.status,
|
|
260
|
+
updatedAt: new Date().toISOString(),
|
|
261
|
+
detail,
|
|
262
|
+
};
|
|
263
|
+
(0, config_1.saveCache)(cache);
|
|
264
|
+
}
|
|
265
|
+
return detail;
|
|
266
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getProductById = getProductById;
|
|
4
|
+
const client_1 = require("./client");
|
|
5
|
+
async function getProductById(config, session, productId) {
|
|
6
|
+
const result = await (0, client_1.requestEbag)(config, session, `/products/${productId}/json`);
|
|
7
|
+
return result.data;
|
|
8
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Config, ProductCacheEntry, SearchResult, Session } from './types';
|
|
2
|
+
export declare const PRODUCT_CACHE_TTL_MS: number;
|
|
3
|
+
export declare function isProductCacheFresh(entry: ProductCacheEntry, now?: number, ttlMs?: number): boolean;
|
|
4
|
+
export declare function searchProducts(config: Config, session: Session, query: string, options?: {
|
|
5
|
+
page?: number;
|
|
6
|
+
limit?: number;
|
|
7
|
+
}): Promise<SearchResult>;
|