@softtynet/zplus-worker 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/README.md +136 -0
- package/dist/automation/HeadlessAutomationEngine.d.ts +12 -0
- package/dist/automation/HeadlessAutomationEngine.js +34 -0
- package/dist/channels/ChannelRunnerRegistry.d.ts +14 -0
- package/dist/channels/ChannelRunnerRegistry.js +65 -0
- package/dist/channels/IChannelRunner.d.ts +10 -0
- package/dist/channels/IChannelRunner.js +2 -0
- package/dist/channels/index.d.ts +6 -0
- package/dist/channels/index.js +22 -0
- package/dist/channels/runners/FacebookChannelRunner.d.ts +19 -0
- package/dist/channels/runners/FacebookChannelRunner.js +47 -0
- package/dist/channels/runners/TelegramChannelRunner.d.ts +19 -0
- package/dist/channels/runners/TelegramChannelRunner.js +47 -0
- package/dist/channels/runners/WhatsAppChannelRunner.d.ts +19 -0
- package/dist/channels/runners/WhatsAppChannelRunner.js +47 -0
- package/dist/channels/runners/ZaloChannelRunner.d.ts +22 -0
- package/dist/channels/runners/ZaloChannelRunner.js +50 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +1409 -0
- package/dist/config/WorkerConfig.d.ts +16 -0
- package/dist/config/WorkerConfig.js +21 -0
- package/dist/engine/WorkerEngine.d.ts +38 -0
- package/dist/engine/WorkerEngine.js +157 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +25 -0
- package/dist/lock/DistributedLockManager.d.ts +40 -0
- package/dist/lock/DistributedLockManager.js +113 -0
- package/dist/notifications/PushNotificationDispatcher.d.ts +14 -0
- package/dist/notifications/PushNotificationDispatcher.js +31 -0
- package/dist/server/WorkerHttpServer.d.ts +25 -0
- package/dist/server/WorkerHttpServer.js +205 -0
- package/dist/sync/CloudPendingMessageQueue.d.ts +27 -0
- package/dist/sync/CloudPendingMessageQueue.js +69 -0
- package/dist/sync/CloudSyncWorker.d.ts +19 -0
- package/dist/sync/CloudSyncWorker.js +53 -0
- package/package.json +32 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 🌐 ZPlus Worker HTTP Ingress Server
|
|
4
|
+
* Cung cấp các endpoint REST cho Desktop Client giao tiếp với 24/7 Cloud Worker:
|
|
5
|
+
* - GET /health: Kiểm tra tình trạng nhịp tim & tài nguyên
|
|
6
|
+
* - POST /api/v1/sentinel/handover: Bàn giao session từ Desktop sang Worker khi tắt máy
|
|
7
|
+
* - POST /api/v1/sentinel/reclaim: Thu hồi quyền phiên khi Desktop mở lại máy tính
|
|
8
|
+
* - GET /api/v1/sync/delta: Trả về tin nhắn phát sinh trong đêm (Delta Sync)
|
|
9
|
+
*/
|
|
10
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.WorkerHttpServer = void 0;
|
|
15
|
+
const http_1 = __importDefault(require("http"));
|
|
16
|
+
const url_1 = require("url");
|
|
17
|
+
const core_1 = require("@zplus/core");
|
|
18
|
+
const ZaloChannelRunner_1 = require("../channels/runners/ZaloChannelRunner");
|
|
19
|
+
const FacebookChannelRunner_1 = require("../channels/runners/FacebookChannelRunner");
|
|
20
|
+
const TelegramChannelRunner_1 = require("../channels/runners/TelegramChannelRunner");
|
|
21
|
+
const WhatsAppChannelRunner_1 = require("../channels/runners/WhatsAppChannelRunner");
|
|
22
|
+
class WorkerHttpServer {
|
|
23
|
+
port;
|
|
24
|
+
engine;
|
|
25
|
+
lockManager;
|
|
26
|
+
deltaQueue;
|
|
27
|
+
logger;
|
|
28
|
+
server = null;
|
|
29
|
+
constructor(port, engine, lockManager, deltaQueue, logger) {
|
|
30
|
+
this.port = port;
|
|
31
|
+
this.engine = engine;
|
|
32
|
+
this.lockManager = lockManager;
|
|
33
|
+
this.deltaQueue = deltaQueue;
|
|
34
|
+
this.logger = logger || (0, core_1.createLogger)("WorkerHttpServer");
|
|
35
|
+
}
|
|
36
|
+
async start() {
|
|
37
|
+
if (this.server)
|
|
38
|
+
return;
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
this.server = http_1.default.createServer((req, res) => {
|
|
41
|
+
this.handleRequest(req, res).catch((err) => {
|
|
42
|
+
this.logger.error("Unhandled HTTP error:", err);
|
|
43
|
+
if (!res.headersSent) {
|
|
44
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
45
|
+
res.end(JSON.stringify({ error: "Internal Server Error" }));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
this.server.listen(this.port, () => {
|
|
50
|
+
this.logger.info(`🚀 Worker HTTP Server listening on port ${this.port}`);
|
|
51
|
+
resolve();
|
|
52
|
+
});
|
|
53
|
+
this.server.on("error", (err) => {
|
|
54
|
+
this.logger.error(`Worker HTTP Server error on port ${this.port}:`, err);
|
|
55
|
+
reject(err);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async stop() {
|
|
60
|
+
if (!this.server)
|
|
61
|
+
return;
|
|
62
|
+
return new Promise((resolve) => {
|
|
63
|
+
this.server?.close(() => {
|
|
64
|
+
this.logger.info("Worker HTTP Server closed.");
|
|
65
|
+
this.server = null;
|
|
66
|
+
resolve();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async handleRequest(req, res) {
|
|
71
|
+
const parsedUrl = new url_1.URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
72
|
+
const pathname = parsedUrl.pathname;
|
|
73
|
+
const method = (req.method || "GET").toUpperCase();
|
|
74
|
+
// CORS headers
|
|
75
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
76
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
77
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Softty-User-Id");
|
|
78
|
+
if (method === "OPTIONS") {
|
|
79
|
+
res.writeHead(204);
|
|
80
|
+
res.end();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// 1. Healthcheck
|
|
84
|
+
if (method === "GET" && pathname === "/health") {
|
|
85
|
+
const metrics = this.engine.getMetrics();
|
|
86
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
87
|
+
res.end(JSON.stringify({
|
|
88
|
+
status: "healthy",
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
pendingDeltaMessages: this.deltaQueue.getCount(),
|
|
91
|
+
metrics,
|
|
92
|
+
}));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// 2. Sentinel Handover (Desktop -> Worker)
|
|
96
|
+
if (method === "POST" && pathname === "/api/v1/sentinel/handover") {
|
|
97
|
+
const body = await this.readJsonBody(req);
|
|
98
|
+
const { deviceId, sessions } = body || {};
|
|
99
|
+
if (!Array.isArray(sessions)) {
|
|
100
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
101
|
+
res.end(JSON.stringify({ error: "Invalid sessions array payload" }));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this.logger.info(`[Handover] Received handover request from device ${deviceId || "unknown"} with ${sessions.length} sessions.`);
|
|
105
|
+
let activatedCount = 0;
|
|
106
|
+
for (const item of sessions) {
|
|
107
|
+
if (!item.id || !item.nightWorkerEnabled)
|
|
108
|
+
continue;
|
|
109
|
+
// Xin Distributed Lock cho Worker
|
|
110
|
+
const lockGranted = this.lockManager.acquireLock(item.id, `worker_${item.id}`);
|
|
111
|
+
if (!lockGranted) {
|
|
112
|
+
this.logger.warn(`Skipping account ${item.id} because lock was not acquired.`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// Tạo Runner phù hợp
|
|
116
|
+
let runner;
|
|
117
|
+
const platform = item.platform || "zalo";
|
|
118
|
+
if (platform === "zalo") {
|
|
119
|
+
runner = new ZaloChannelRunner_1.ZaloChannelRunner(item.id, item.sessionData);
|
|
120
|
+
}
|
|
121
|
+
else if (platform === "facebook") {
|
|
122
|
+
runner = new FacebookChannelRunner_1.FacebookChannelRunner(item.id, item.sessionData);
|
|
123
|
+
}
|
|
124
|
+
else if (platform === "telegram") {
|
|
125
|
+
runner = new TelegramChannelRunner_1.TelegramChannelRunner(item.id, item.sessionData);
|
|
126
|
+
}
|
|
127
|
+
else if (platform === "whatsapp") {
|
|
128
|
+
runner = new WhatsAppChannelRunner_1.WhatsAppChannelRunner(item.id, item.sessionData);
|
|
129
|
+
}
|
|
130
|
+
if (runner) {
|
|
131
|
+
this.engine.channelRunnerRegistry.register(runner);
|
|
132
|
+
await runner.start();
|
|
133
|
+
this.engine.registerAccount({
|
|
134
|
+
id: item.id,
|
|
135
|
+
platform,
|
|
136
|
+
accountName: item.accountName || item.id,
|
|
137
|
+
status: "active",
|
|
138
|
+
nightWorkerEnabled: true,
|
|
139
|
+
});
|
|
140
|
+
activatedCount++;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
144
|
+
res.end(JSON.stringify({
|
|
145
|
+
success: true,
|
|
146
|
+
message: "Sessions handed over successfully",
|
|
147
|
+
activatedCount,
|
|
148
|
+
timestamp: Date.now(),
|
|
149
|
+
}));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// 3. Sentinel Reclaim (Desktop wakes up, reclaims lock & forces worker to close WSS)
|
|
153
|
+
if (method === "POST" && pathname === "/api/v1/sentinel/reclaim") {
|
|
154
|
+
const body = await this.readJsonBody(req);
|
|
155
|
+
const { deviceId } = body || {};
|
|
156
|
+
this.logger.info(`[Reclaim] Master device ${deviceId || "desktop"} reclaiming all active sessions. Stopping cloud runners...`);
|
|
157
|
+
// Ngắt tất cả runners trên Cloud để nhường quyền kết nối cho Desktop
|
|
158
|
+
const count = this.engine.channelRunnerRegistry.getCount();
|
|
159
|
+
await this.engine.channelRunnerRegistry.stopAll();
|
|
160
|
+
// Giải phóng khóa
|
|
161
|
+
this.lockManager.releaseAllForOwner(`worker`);
|
|
162
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
163
|
+
res.end(JSON.stringify({
|
|
164
|
+
success: true,
|
|
165
|
+
reclaimedCount: count,
|
|
166
|
+
timestamp: Date.now(),
|
|
167
|
+
}));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// 4. Delta Sync (Desktop kéo tin nhắn phát sinh trong đêm)
|
|
171
|
+
if (method === "GET" && pathname === "/api/v1/sync/delta") {
|
|
172
|
+
const accountId = parsedUrl.searchParams.get("accountId") || undefined;
|
|
173
|
+
const since = parseInt(parsedUrl.searchParams.get("since") || "0", 10);
|
|
174
|
+
const deltas = this.deltaQueue.getDeltas(accountId, since);
|
|
175
|
+
this.logger.info(`[DeltaSync] Serving ${deltas.length} night messages (since: ${since}, account: ${accountId || "all"})`);
|
|
176
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
177
|
+
res.end(JSON.stringify({
|
|
178
|
+
success: true,
|
|
179
|
+
messages: deltas,
|
|
180
|
+
count: deltas.length,
|
|
181
|
+
syncedTimestamp: Date.now(),
|
|
182
|
+
}));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
186
|
+
res.end(JSON.stringify({ error: "Endpoint not found" }));
|
|
187
|
+
}
|
|
188
|
+
readJsonBody(req) {
|
|
189
|
+
return new Promise((resolve) => {
|
|
190
|
+
let bodyStr = "";
|
|
191
|
+
req.on("data", (chunk) => {
|
|
192
|
+
bodyStr += chunk;
|
|
193
|
+
});
|
|
194
|
+
req.on("end", () => {
|
|
195
|
+
try {
|
|
196
|
+
resolve(JSON.parse(bodyStr));
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
resolve({});
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.WorkerHttpServer = WorkerHttpServer;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 📥 Cloud Pending Message Queue
|
|
3
|
+
* Hàng đợi lưu tạm thời các tin nhắn khách hàng gửi đến trong lúc tắt máy tính (ca đêm)
|
|
4
|
+
* để cung cấp cho API GET /api/v1/sync/delta khi Desktop khởi động lại.
|
|
5
|
+
*/
|
|
6
|
+
import { UnifiedMessage } from "@zplus/contracts";
|
|
7
|
+
import { ILogger } from "@zplus/core";
|
|
8
|
+
export declare class CloudPendingMessageQueue {
|
|
9
|
+
private readonly logger;
|
|
10
|
+
private readonly queue;
|
|
11
|
+
private readonly maxCapacity;
|
|
12
|
+
constructor(maxCapacity?: number, logger?: ILogger);
|
|
13
|
+
/**
|
|
14
|
+
* Đưa tin nhắn mới nhận được trong lúc gác đền vào hàng đợi
|
|
15
|
+
*/
|
|
16
|
+
enqueue(message: UnifiedMessage): void;
|
|
17
|
+
/**
|
|
18
|
+
* Lấy danh sách tin nhắn phát sinh kể từ mốc thời gian sinceTimestamp
|
|
19
|
+
*/
|
|
20
|
+
getDeltas(accountId?: string, sinceTimestamp?: number): UnifiedMessage[];
|
|
21
|
+
/**
|
|
22
|
+
* Đánh dấu đã đồng bộ và dọn dẹp các tin nhắn cũ hơn upToTimestamp
|
|
23
|
+
*/
|
|
24
|
+
purgeSynced(upToTimestamp: number, accountId?: string): number;
|
|
25
|
+
getCount(): number;
|
|
26
|
+
clear(): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 📥 Cloud Pending Message Queue
|
|
4
|
+
* Hàng đợi lưu tạm thời các tin nhắn khách hàng gửi đến trong lúc tắt máy tính (ca đêm)
|
|
5
|
+
* để cung cấp cho API GET /api/v1/sync/delta khi Desktop khởi động lại.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.CloudPendingMessageQueue = void 0;
|
|
9
|
+
const core_1 = require("@zplus/core");
|
|
10
|
+
class CloudPendingMessageQueue {
|
|
11
|
+
logger;
|
|
12
|
+
queue = [];
|
|
13
|
+
maxCapacity;
|
|
14
|
+
constructor(maxCapacity = 10000, logger) {
|
|
15
|
+
this.maxCapacity = maxCapacity;
|
|
16
|
+
this.logger = logger || (0, core_1.createLogger)("CloudPendingMessageQueue");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Đưa tin nhắn mới nhận được trong lúc gác đền vào hàng đợi
|
|
20
|
+
*/
|
|
21
|
+
enqueue(message) {
|
|
22
|
+
if (this.queue.length >= this.maxCapacity) {
|
|
23
|
+
const removed = this.queue.shift();
|
|
24
|
+
this.logger.warn(`Queue capacity reached (${this.maxCapacity}). Dropped oldest message: ${removed?.id}`);
|
|
25
|
+
}
|
|
26
|
+
this.queue.push(message);
|
|
27
|
+
this.logger.debug(`Enqueued pending message ${message.id} for account ${message.accountId} (Total pending: ${this.queue.length})`);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Lấy danh sách tin nhắn phát sinh kể từ mốc thời gian sinceTimestamp
|
|
31
|
+
*/
|
|
32
|
+
getDeltas(accountId, sinceTimestamp = 0) {
|
|
33
|
+
return this.queue.filter((msg) => {
|
|
34
|
+
const matchAccount = !accountId || msg.accountId === accountId;
|
|
35
|
+
const matchTime = msg.timestamp >= sinceTimestamp;
|
|
36
|
+
return matchAccount && matchTime;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Đánh dấu đã đồng bộ và dọn dẹp các tin nhắn cũ hơn upToTimestamp
|
|
41
|
+
*/
|
|
42
|
+
purgeSynced(upToTimestamp, accountId) {
|
|
43
|
+
const initialLen = this.queue.length;
|
|
44
|
+
const removeIndices = [];
|
|
45
|
+
for (let i = 0; i < this.queue.length; i++) {
|
|
46
|
+
const msg = this.queue[i];
|
|
47
|
+
if (msg.timestamp <= upToTimestamp &&
|
|
48
|
+
(!accountId || msg.accountId === accountId)) {
|
|
49
|
+
removeIndices.push(i);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Xóa từ cuối về đầu
|
|
53
|
+
for (let i = removeIndices.length - 1; i >= 0; i--) {
|
|
54
|
+
this.queue.splice(removeIndices[i], 1);
|
|
55
|
+
}
|
|
56
|
+
const removedCount = initialLen - this.queue.length;
|
|
57
|
+
if (removedCount > 0) {
|
|
58
|
+
this.logger.info(`Purged ${removedCount} synced delta messages from queue.`);
|
|
59
|
+
}
|
|
60
|
+
return removedCount;
|
|
61
|
+
}
|
|
62
|
+
getCount() {
|
|
63
|
+
return this.queue.length;
|
|
64
|
+
}
|
|
65
|
+
clear() {
|
|
66
|
+
this.queue.length = 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.CloudPendingMessageQueue = CloudPendingMessageQueue;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ILogger } from "@zplus/core";
|
|
2
|
+
import { SyncOutboxRecord } from "@zplus/contracts";
|
|
3
|
+
export interface CloudSyncWorkerConfig {
|
|
4
|
+
endpoint: string;
|
|
5
|
+
projectId: string;
|
|
6
|
+
pollIntervalMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class CloudSyncWorker {
|
|
9
|
+
private readonly config;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private isRunning;
|
|
12
|
+
private timer;
|
|
13
|
+
constructor(config: CloudSyncWorkerConfig, logger?: ILogger);
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
stop(): Promise<void>;
|
|
16
|
+
pushOutboxRecord(record: SyncOutboxRecord): Promise<boolean>;
|
|
17
|
+
private scheduleNextPoll;
|
|
18
|
+
private syncPendingDeltas;
|
|
19
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CloudSyncWorker = void 0;
|
|
4
|
+
const core_1 = require("@zplus/core");
|
|
5
|
+
class CloudSyncWorker {
|
|
6
|
+
config;
|
|
7
|
+
logger;
|
|
8
|
+
isRunning = false;
|
|
9
|
+
timer = null;
|
|
10
|
+
constructor(config, logger) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.logger = logger || (0, core_1.createLogger)("CloudSyncWorker");
|
|
13
|
+
}
|
|
14
|
+
async start() {
|
|
15
|
+
if (this.isRunning)
|
|
16
|
+
return;
|
|
17
|
+
this.isRunning = true;
|
|
18
|
+
this.logger.info(`Starting 24/7 Cloud Sync Worker (Endpoint: ${this.config.endpoint})...`);
|
|
19
|
+
this.scheduleNextPoll();
|
|
20
|
+
}
|
|
21
|
+
async stop() {
|
|
22
|
+
this.isRunning = false;
|
|
23
|
+
if (this.timer) {
|
|
24
|
+
clearTimeout(this.timer);
|
|
25
|
+
this.timer = null;
|
|
26
|
+
}
|
|
27
|
+
this.logger.info("Cloud Sync Worker stopped.");
|
|
28
|
+
}
|
|
29
|
+
async pushOutboxRecord(record) {
|
|
30
|
+
this.logger.debug(`Queued outbox record for sync: ${record.id} (${record.tableName})`);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
scheduleNextPoll() {
|
|
34
|
+
if (!this.isRunning)
|
|
35
|
+
return;
|
|
36
|
+
const interval = this.config.pollIntervalMs || 10000;
|
|
37
|
+
this.timer = setTimeout(async () => {
|
|
38
|
+
try {
|
|
39
|
+
await this.syncPendingDeltas();
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
this.logger.error("Error during delta sync poll:", err);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
this.scheduleNextPoll();
|
|
46
|
+
}
|
|
47
|
+
}, interval);
|
|
48
|
+
}
|
|
49
|
+
async syncPendingDeltas() {
|
|
50
|
+
// Polls or checks incoming cloud delta changes
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.CloudSyncWorker = CloudSyncWorker;
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@softtynet/zplus-worker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ZPlus 24/7 Headless Automation & Omnichannel Worker Engine",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"zplus-worker": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc && npm run bundle",
|
|
18
|
+
"bundle": "esbuild src/cli.ts --bundle --platform=node --target=node18 --outfile=dist/cli.js",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"start": "node dist/cli.js",
|
|
22
|
+
"dev": "node --loader ts-node/esm src/cli.ts"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@zplus/contracts": "^1.0.0",
|
|
26
|
+
"@zplus/core": "^1.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"esbuild": "^0.25.12",
|
|
30
|
+
"vitest": "^4.0.0"
|
|
31
|
+
}
|
|
32
|
+
}
|