@jackle.dev/zalox 1.0.1
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/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/cli/commands/admin.d.ts +17 -0
- package/dist/cli/commands/admin.d.ts.map +1 -0
- package/dist/cli/commands/admin.js +359 -0
- package/dist/cli/commands/admin.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +3 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +88 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/autoreply.d.ts +12 -0
- package/dist/cli/commands/autoreply.d.ts.map +1 -0
- package/dist/cli/commands/autoreply.js +162 -0
- package/dist/cli/commands/autoreply.js.map +1 -0
- package/dist/cli/commands/bulk.d.ts +9 -0
- package/dist/cli/commands/bulk.d.ts.map +1 -0
- package/dist/cli/commands/bulk.js +169 -0
- package/dist/cli/commands/bulk.js.map +1 -0
- package/dist/cli/commands/config.d.ts +14 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +122 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/conv.d.ts +3 -0
- package/dist/cli/commands/conv.d.ts.map +1 -0
- package/dist/cli/commands/conv.js +229 -0
- package/dist/cli/commands/conv.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +13 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -0
- package/dist/cli/commands/daemon.js +102 -0
- package/dist/cli/commands/daemon.js.map +1 -0
- package/dist/cli/commands/export.d.ts +10 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +98 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/friend.d.ts +13 -0
- package/dist/cli/commands/friend.d.ts.map +1 -0
- package/dist/cli/commands/friend.js +337 -0
- package/dist/cli/commands/friend.js.map +1 -0
- package/dist/cli/commands/group-settings.d.ts +11 -0
- package/dist/cli/commands/group-settings.d.ts.map +1 -0
- package/dist/cli/commands/group-settings.js +154 -0
- package/dist/cli/commands/group-settings.js.map +1 -0
- package/dist/cli/commands/group.d.ts +14 -0
- package/dist/cli/commands/group.d.ts.map +1 -0
- package/dist/cli/commands/group.js +365 -0
- package/dist/cli/commands/group.js.map +1 -0
- package/dist/cli/commands/license.d.ts +13 -0
- package/dist/cli/commands/license.d.ts.map +1 -0
- package/dist/cli/commands/license.js +218 -0
- package/dist/cli/commands/license.js.map +1 -0
- package/dist/cli/commands/listen.d.ts +3 -0
- package/dist/cli/commands/listen.d.ts.map +1 -0
- package/dist/cli/commands/listen.js +177 -0
- package/dist/cli/commands/listen.js.map +1 -0
- package/dist/cli/commands/me.d.ts +9 -0
- package/dist/cli/commands/me.d.ts.map +1 -0
- package/dist/cli/commands/me.js +135 -0
- package/dist/cli/commands/me.js.map +1 -0
- package/dist/cli/commands/msg.d.ts +11 -0
- package/dist/cli/commands/msg.d.ts.map +1 -0
- package/dist/cli/commands/msg.js +255 -0
- package/dist/cli/commands/msg.js.map +1 -0
- package/dist/cli/commands/profile.d.ts +3 -0
- package/dist/cli/commands/profile.d.ts.map +1 -0
- package/dist/cli/commands/profile.js +50 -0
- package/dist/cli/commands/profile.js.map +1 -0
- package/dist/cli/commands/schedule.d.ts +12 -0
- package/dist/cli/commands/schedule.d.ts.map +1 -0
- package/dist/cli/commands/schedule.js +175 -0
- package/dist/cli/commands/schedule.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +3 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +87 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/template.d.ts +12 -0
- package/dist/cli/commands/template.d.ts.map +1 -0
- package/dist/cli/commands/template.js +163 -0
- package/dist/cli/commands/template.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +116 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +63 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +144 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/core/autoreply.d.ts +57 -0
- package/dist/core/autoreply.d.ts.map +1 -0
- package/dist/core/autoreply.js +159 -0
- package/dist/core/autoreply.js.map +1 -0
- package/dist/core/bulk.d.ts +36 -0
- package/dist/core/bulk.d.ts.map +1 -0
- package/dist/core/bulk.js +117 -0
- package/dist/core/bulk.js.map +1 -0
- package/dist/core/client.d.ts +8 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +91 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/daemon.d.ts +30 -0
- package/dist/core/daemon.d.ts.map +1 -0
- package/dist/core/daemon.js +213 -0
- package/dist/core/daemon.js.map +1 -0
- package/dist/core/dm-commands.d.ts +41 -0
- package/dist/core/dm-commands.d.ts.map +1 -0
- package/dist/core/dm-commands.js +313 -0
- package/dist/core/dm-commands.js.map +1 -0
- package/dist/core/export.d.ts +20 -0
- package/dist/core/export.d.ts.map +1 -0
- package/dist/core/export.js +92 -0
- package/dist/core/export.js.map +1 -0
- package/dist/core/gate.d.ts +39 -0
- package/dist/core/gate.d.ts.map +1 -0
- package/dist/core/gate.js +75 -0
- package/dist/core/gate.js.map +1 -0
- package/dist/core/group-settings.d.ts +35 -0
- package/dist/core/group-settings.d.ts.map +1 -0
- package/dist/core/group-settings.js +70 -0
- package/dist/core/group-settings.js.map +1 -0
- package/dist/core/index.d.ts +22 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +12 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/license.d.ts +103 -0
- package/dist/core/license.d.ts.map +1 -0
- package/dist/core/license.js +444 -0
- package/dist/core/license.js.map +1 -0
- package/dist/core/scheduler.d.ts +45 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +203 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/templates.d.ts +35 -0
- package/dist/core/templates.d.ts.map +1 -0
- package/dist/core/templates.js +107 -0
- package/dist/core/templates.js.map +1 -0
- package/dist/core/types.d.ts +57 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +10 -0
- package/dist/core/types.js.map +1 -0
- package/dist/server/api.d.ts +2 -0
- package/dist/server/api.d.ts.map +1 -0
- package/dist/server/api.js +79 -0
- package/dist/server/api.js.map +1 -0
- package/dist/server/index.d.ts +16 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +48 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/license-api.d.ts +55 -0
- package/dist/server/license-api.d.ts.map +1 -0
- package/dist/server/license-api.js +496 -0
- package/dist/server/license-api.js.map +1 -0
- package/dist/server/middleware.d.ts +18 -0
- package/dist/server/middleware.d.ts.map +1 -0
- package/dist/server/middleware.js +92 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/webhook.d.ts +10 -0
- package/dist/server/webhook.d.ts.map +1 -0
- package/dist/server/webhook.js +53 -0
- package/dist/server/webhook.js.map +1 -0
- package/dist/server/ws.d.ts +66 -0
- package/dist/server/ws.d.ts.map +1 -0
- package/dist/server/ws.js +203 -0
- package/dist/server/ws.js.map +1 -0
- package/dist/utils/cache.d.ts +35 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +78 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/config.d.ts +16 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +88 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +51 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAGvD;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CA2BzD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,iBAAiB,CAgBjD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,iBAAiB,CAoBhD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,MAAM,EAAU,GAAG,iBAAiB,CAyB3E"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key authentication middleware
|
|
3
|
+
*/
|
|
4
|
+
export function apiKeyAuth(key) {
|
|
5
|
+
return async (c, next) => {
|
|
6
|
+
// Skip auth for health check
|
|
7
|
+
if (c.req.path === '/api/health') {
|
|
8
|
+
return next();
|
|
9
|
+
}
|
|
10
|
+
const provided = c.req.header('X-API-Key') || c.req.query('api_key');
|
|
11
|
+
if (!provided) {
|
|
12
|
+
return c.json({
|
|
13
|
+
success: false,
|
|
14
|
+
error: 'Missing API key. Provide X-API-Key header or api_key query parameter.',
|
|
15
|
+
timestamp: new Date().toISOString(),
|
|
16
|
+
}, 401);
|
|
17
|
+
}
|
|
18
|
+
if (provided !== key) {
|
|
19
|
+
return c.json({
|
|
20
|
+
success: false,
|
|
21
|
+
error: 'Invalid API key.',
|
|
22
|
+
timestamp: new Date().toISOString(),
|
|
23
|
+
}, 403);
|
|
24
|
+
}
|
|
25
|
+
await next();
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Request logging middleware
|
|
30
|
+
*/
|
|
31
|
+
export function requestLogger() {
|
|
32
|
+
return async (c, next) => {
|
|
33
|
+
const start = Date.now();
|
|
34
|
+
const method = c.req.method;
|
|
35
|
+
const path = c.req.path;
|
|
36
|
+
await next();
|
|
37
|
+
const duration = Date.now() - start;
|
|
38
|
+
const status = c.res.status;
|
|
39
|
+
const statusColor = status >= 400 ? '\x1b[31m' : status >= 300 ? '\x1b[33m' : '\x1b[32m';
|
|
40
|
+
console.log(`\x1b[90m${new Date().toISOString()}\x1b[0m ${method.padEnd(7)} ${path} ${statusColor}${status}\x1b[0m \x1b[90m${duration}ms\x1b[0m`);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Global error handler middleware
|
|
45
|
+
*/
|
|
46
|
+
export function errorHandler() {
|
|
47
|
+
return async (c, next) => {
|
|
48
|
+
try {
|
|
49
|
+
await next();
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : 'Internal server error';
|
|
53
|
+
const stack = err instanceof Error ? err.stack : undefined;
|
|
54
|
+
console.error(`\x1b[31m[ERROR]\x1b[0m ${message}`);
|
|
55
|
+
if (stack) {
|
|
56
|
+
console.error(`\x1b[90m${stack}\x1b[0m`);
|
|
57
|
+
}
|
|
58
|
+
return c.json({
|
|
59
|
+
success: false,
|
|
60
|
+
error: message,
|
|
61
|
+
timestamp: new Date().toISOString(),
|
|
62
|
+
}, 500);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* CORS middleware
|
|
68
|
+
*/
|
|
69
|
+
export function corsMiddleware(origins = ['*']) {
|
|
70
|
+
return async (c, next) => {
|
|
71
|
+
const origin = c.req.header('Origin') || '';
|
|
72
|
+
const allowOrigin = origins.includes('*') ? '*' : (origins.includes(origin) ? origin : '');
|
|
73
|
+
if (c.req.method === 'OPTIONS') {
|
|
74
|
+
return new Response(null, {
|
|
75
|
+
status: 204,
|
|
76
|
+
headers: {
|
|
77
|
+
'Access-Control-Allow-Origin': allowOrigin || origins[0] || '*',
|
|
78
|
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
|
79
|
+
'Access-Control-Allow-Headers': 'Content-Type, X-API-Key, Authorization',
|
|
80
|
+
'Access-Control-Max-Age': '86400',
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
await next();
|
|
85
|
+
if (allowOrigin) {
|
|
86
|
+
c.header('Access-Control-Allow-Origin', allowOrigin);
|
|
87
|
+
c.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
88
|
+
c.header('Access-Control-Allow-Headers', 'Content-Type, X-API-Key, Authorization');
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/server/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAKlC,qBAAa,cAAc;IACzB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAM3C,KAAK;YAkBE,OAAO;CA2BtB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { logger } from '../utils/logger.js';
|
|
2
|
+
import fetch from 'node-fetch';
|
|
3
|
+
export class WebhookManager {
|
|
4
|
+
api;
|
|
5
|
+
url;
|
|
6
|
+
secret;
|
|
7
|
+
constructor(api, url, secret) {
|
|
8
|
+
this.api = api;
|
|
9
|
+
this.url = url;
|
|
10
|
+
this.secret = secret;
|
|
11
|
+
}
|
|
12
|
+
start() {
|
|
13
|
+
logger.info(`Starting webhook forwarding to ${this.url}`);
|
|
14
|
+
this.api.listener.on('message', async (msg) => {
|
|
15
|
+
await this.forward('message', msg);
|
|
16
|
+
});
|
|
17
|
+
this.api.listener.on('group_event', async (msg) => {
|
|
18
|
+
await this.forward('group_event', msg);
|
|
19
|
+
});
|
|
20
|
+
this.api.listener.on('reaction', async (msg) => {
|
|
21
|
+
await this.forward('reaction', msg);
|
|
22
|
+
});
|
|
23
|
+
this.api.listener.start();
|
|
24
|
+
}
|
|
25
|
+
async forward(event, data) {
|
|
26
|
+
try {
|
|
27
|
+
const payload = {
|
|
28
|
+
event,
|
|
29
|
+
timestamp: Date.now(),
|
|
30
|
+
data,
|
|
31
|
+
// TODO: Sign payload with secret if provided
|
|
32
|
+
};
|
|
33
|
+
const response = await fetch(this.url, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
'User-Agent': 'ZaloX-Webhook/1.0',
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify(payload),
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
logger.warn(`Webhook failed: ${response.status} ${response.statusText}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
logger.debug(`Webhook sent: ${event}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
logger.error(`Webhook error: ${err.message}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/server/webhook.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,OAAO,cAAc;IACjB,GAAG,CAAM;IACT,GAAG,CAAS;IACZ,MAAM,CAAU;IAExB,YAAY,GAAQ,EAAE,GAAW,EAAE,MAAe;QAChD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEM,KAAK;QACV,MAAM,CAAC,IAAI,CAAC,kCAAkC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAE1D,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC5C,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAChD,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7C,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,IAAS;QAC5C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG;gBACd,KAAK;gBACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,IAAI;gBACJ,6CAA6C;aAC9C,CAAC;YAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,YAAY,EAAE,mBAAmB;iBAClC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;aAC9B,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,mBAAmB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YAC3E,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,iBAAiB,KAAK,EAAE,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,kBAAkB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ServerWebSocket } from 'bun';
|
|
2
|
+
export interface WSClient {
|
|
3
|
+
id: string;
|
|
4
|
+
ws: ServerWebSocket<WSClientData>;
|
|
5
|
+
subscribedEvents: string[];
|
|
6
|
+
connectedAt: Date;
|
|
7
|
+
lastPing: Date;
|
|
8
|
+
}
|
|
9
|
+
export interface WSClientData {
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
12
|
+
export interface WSMessage {
|
|
13
|
+
type: string;
|
|
14
|
+
data: unknown;
|
|
15
|
+
timestamp: string;
|
|
16
|
+
id: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Manages WebSocket connections for real-time event streaming
|
|
20
|
+
*/
|
|
21
|
+
export declare class WebSocketManager {
|
|
22
|
+
private clients;
|
|
23
|
+
private heartbeatInterval;
|
|
24
|
+
constructor();
|
|
25
|
+
/**
|
|
26
|
+
* Handle new WebSocket connection
|
|
27
|
+
*/
|
|
28
|
+
addClient(ws: ServerWebSocket<WSClientData>): string;
|
|
29
|
+
/**
|
|
30
|
+
* Handle WebSocket disconnection
|
|
31
|
+
*/
|
|
32
|
+
removeClient(id: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Handle incoming WebSocket message
|
|
35
|
+
*/
|
|
36
|
+
handleMessage(id: string, raw: string | Buffer): void;
|
|
37
|
+
/**
|
|
38
|
+
* Broadcast an event to all connected clients
|
|
39
|
+
*/
|
|
40
|
+
broadcast(eventType: string, data: unknown): void;
|
|
41
|
+
/**
|
|
42
|
+
* Get connected client count
|
|
43
|
+
*/
|
|
44
|
+
getClientCount(): number;
|
|
45
|
+
/**
|
|
46
|
+
* Get all client info (for health/status endpoints)
|
|
47
|
+
*/
|
|
48
|
+
getClients(): {
|
|
49
|
+
id: string;
|
|
50
|
+
subscribedEvents: string[];
|
|
51
|
+
connectedAt: string;
|
|
52
|
+
}[];
|
|
53
|
+
/**
|
|
54
|
+
* Send a message to a specific WebSocket
|
|
55
|
+
*/
|
|
56
|
+
private sendTo;
|
|
57
|
+
/**
|
|
58
|
+
* Start heartbeat interval to detect dead connections
|
|
59
|
+
*/
|
|
60
|
+
private startHeartbeat;
|
|
61
|
+
/**
|
|
62
|
+
* Stop the heartbeat and close all connections
|
|
63
|
+
*/
|
|
64
|
+
stop(): void;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=ws.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/server/ws.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,KAAK,CAAC;AAG3C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAClC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,WAAW,EAAE,IAAI,CAAC;IAClB,QAAQ,EAAE,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,iBAAiB,CAA+C;;IAMxE;;OAEG;IACH,SAAS,CAAC,EAAE,EAAE,eAAe,CAAC,YAAY,CAAC,GAAG,MAAM;IAiCpD;;OAEG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK9B;;OAEG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA0DrD;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAyBjD;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,UAAU,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE;IAQ/E;;OAEG;IACH,OAAO,CAAC,MAAM;IAQd;;OAEG;IACH,OAAO,CAAC,cAAc;IAuBtB;;OAEG;IACH,IAAI,IAAI,IAAI;CAgBb"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Manages WebSocket connections for real-time event streaming
|
|
4
|
+
*/
|
|
5
|
+
export class WebSocketManager {
|
|
6
|
+
clients = new Map();
|
|
7
|
+
heartbeatInterval = null;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.startHeartbeat();
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Handle new WebSocket connection
|
|
13
|
+
*/
|
|
14
|
+
addClient(ws) {
|
|
15
|
+
const id = randomUUID();
|
|
16
|
+
const client = {
|
|
17
|
+
id,
|
|
18
|
+
ws,
|
|
19
|
+
subscribedEvents: [],
|
|
20
|
+
connectedAt: new Date(),
|
|
21
|
+
lastPing: new Date(),
|
|
22
|
+
};
|
|
23
|
+
this.clients.set(id, client);
|
|
24
|
+
ws.data = { id };
|
|
25
|
+
// Send welcome message
|
|
26
|
+
this.sendTo(ws, {
|
|
27
|
+
type: 'connected',
|
|
28
|
+
data: {
|
|
29
|
+
clientId: id,
|
|
30
|
+
message: 'Connected to ZaloX event stream',
|
|
31
|
+
availableEvents: [
|
|
32
|
+
'message', 'typing', 'reaction', 'undo',
|
|
33
|
+
'friend_event', 'group_event',
|
|
34
|
+
'seen_messages', 'delivered_messages',
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
timestamp: new Date().toISOString(),
|
|
38
|
+
id: randomUUID(),
|
|
39
|
+
});
|
|
40
|
+
console.log(`\x1b[36m[ws]\x1b[0m Client connected: ${id} (total: ${this.clients.size})`);
|
|
41
|
+
return id;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Handle WebSocket disconnection
|
|
45
|
+
*/
|
|
46
|
+
removeClient(id) {
|
|
47
|
+
this.clients.delete(id);
|
|
48
|
+
console.log(`\x1b[36m[ws]\x1b[0m Client disconnected: ${id} (total: ${this.clients.size})`);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Handle incoming WebSocket message
|
|
52
|
+
*/
|
|
53
|
+
handleMessage(id, raw) {
|
|
54
|
+
const client = this.clients.get(id);
|
|
55
|
+
if (!client)
|
|
56
|
+
return;
|
|
57
|
+
try {
|
|
58
|
+
const msg = JSON.parse(typeof raw === 'string' ? raw : raw.toString());
|
|
59
|
+
switch (msg.type) {
|
|
60
|
+
case 'ping':
|
|
61
|
+
client.lastPing = new Date();
|
|
62
|
+
this.sendTo(client.ws, {
|
|
63
|
+
type: 'pong',
|
|
64
|
+
data: { serverTime: new Date().toISOString() },
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
id: randomUUID(),
|
|
67
|
+
});
|
|
68
|
+
break;
|
|
69
|
+
case 'subscribe':
|
|
70
|
+
if (Array.isArray(msg.events)) {
|
|
71
|
+
client.subscribedEvents = msg.events;
|
|
72
|
+
this.sendTo(client.ws, {
|
|
73
|
+
type: 'subscribed',
|
|
74
|
+
data: { events: client.subscribedEvents },
|
|
75
|
+
timestamp: new Date().toISOString(),
|
|
76
|
+
id: randomUUID(),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
case 'unsubscribe':
|
|
81
|
+
client.subscribedEvents = [];
|
|
82
|
+
this.sendTo(client.ws, {
|
|
83
|
+
type: 'unsubscribed',
|
|
84
|
+
data: {},
|
|
85
|
+
timestamp: new Date().toISOString(),
|
|
86
|
+
id: randomUUID(),
|
|
87
|
+
});
|
|
88
|
+
break;
|
|
89
|
+
default:
|
|
90
|
+
this.sendTo(client.ws, {
|
|
91
|
+
type: 'error',
|
|
92
|
+
data: { message: `Unknown message type: ${msg.type}` },
|
|
93
|
+
timestamp: new Date().toISOString(),
|
|
94
|
+
id: randomUUID(),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
this.sendTo(client.ws, {
|
|
100
|
+
type: 'error',
|
|
101
|
+
data: { message: 'Invalid JSON message' },
|
|
102
|
+
timestamp: new Date().toISOString(),
|
|
103
|
+
id: randomUUID(),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Broadcast an event to all connected clients
|
|
109
|
+
*/
|
|
110
|
+
broadcast(eventType, data) {
|
|
111
|
+
const message = {
|
|
112
|
+
type: eventType,
|
|
113
|
+
data,
|
|
114
|
+
timestamp: new Date().toISOString(),
|
|
115
|
+
id: randomUUID(),
|
|
116
|
+
};
|
|
117
|
+
const payload = JSON.stringify(message);
|
|
118
|
+
for (const client of this.clients.values()) {
|
|
119
|
+
// If client has subscriptions, only send matching events
|
|
120
|
+
if (client.subscribedEvents.length > 0 && !client.subscribedEvents.includes(eventType)) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
client.ws.send(payload);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Client likely disconnected
|
|
128
|
+
this.clients.delete(client.id);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get connected client count
|
|
134
|
+
*/
|
|
135
|
+
getClientCount() {
|
|
136
|
+
return this.clients.size;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get all client info (for health/status endpoints)
|
|
140
|
+
*/
|
|
141
|
+
getClients() {
|
|
142
|
+
return Array.from(this.clients.values()).map(c => ({
|
|
143
|
+
id: c.id,
|
|
144
|
+
subscribedEvents: c.subscribedEvents,
|
|
145
|
+
connectedAt: c.connectedAt.toISOString(),
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Send a message to a specific WebSocket
|
|
150
|
+
*/
|
|
151
|
+
sendTo(ws, message) {
|
|
152
|
+
try {
|
|
153
|
+
ws.send(JSON.stringify(message));
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Ignore send errors
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Start heartbeat interval to detect dead connections
|
|
161
|
+
*/
|
|
162
|
+
startHeartbeat() {
|
|
163
|
+
this.heartbeatInterval = setInterval(() => {
|
|
164
|
+
const now = Date.now();
|
|
165
|
+
const timeout = 60_000; // 60 seconds
|
|
166
|
+
for (const [id, client] of this.clients) {
|
|
167
|
+
if (now - client.lastPing.getTime() > timeout) {
|
|
168
|
+
try {
|
|
169
|
+
// Send a server ping to keep alive
|
|
170
|
+
this.sendTo(client.ws, {
|
|
171
|
+
type: 'heartbeat',
|
|
172
|
+
data: { serverTime: new Date().toISOString() },
|
|
173
|
+
timestamp: new Date().toISOString(),
|
|
174
|
+
id: randomUUID(),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
this.clients.delete(id);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}, 30_000);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Stop the heartbeat and close all connections
|
|
186
|
+
*/
|
|
187
|
+
stop() {
|
|
188
|
+
if (this.heartbeatInterval) {
|
|
189
|
+
clearInterval(this.heartbeatInterval);
|
|
190
|
+
this.heartbeatInterval = null;
|
|
191
|
+
}
|
|
192
|
+
for (const client of this.clients.values()) {
|
|
193
|
+
try {
|
|
194
|
+
client.ws.close(1000, 'Server shutting down');
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Ignore close errors
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
this.clients.clear();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=ws.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws.js","sourceRoot":"","sources":["../../src/server/ws.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZaloX — File-based cache for cross-process data sharing
|
|
3
|
+
*
|
|
4
|
+
* Problem: Each `zca` CLI invocation is a separate process.
|
|
5
|
+
* zca-js login() creates a new Zalo session, invalidating the previous one.
|
|
6
|
+
* This kills any active WebSocket listener.
|
|
7
|
+
*
|
|
8
|
+
* Solution: Cache API responses to disk after the first login.
|
|
9
|
+
* Subsequent commands read from cache instead of logging in again.
|
|
10
|
+
*/
|
|
11
|
+
export interface CacheEntry<T> {
|
|
12
|
+
data: T;
|
|
13
|
+
cachedAt: number;
|
|
14
|
+
profile: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Write data to cache file
|
|
18
|
+
*/
|
|
19
|
+
export declare function writeCache<T>(profile: string, key: string, data: T): void;
|
|
20
|
+
/**
|
|
21
|
+
* Read data from cache file
|
|
22
|
+
* @param maxAgeMs - Maximum age of cache in milliseconds (default: 1 hour)
|
|
23
|
+
* @returns cached data or null if cache miss/expired
|
|
24
|
+
*/
|
|
25
|
+
export declare function readCache<T>(profile: string, key: string, maxAgeMs?: number): T | null;
|
|
26
|
+
/**
|
|
27
|
+
* Read cache regardless of age (for offline mode)
|
|
28
|
+
*/
|
|
29
|
+
export declare function readCacheAny<T>(profile: string, key: string): T | null;
|
|
30
|
+
export declare const CACHE_KEYS: {
|
|
31
|
+
readonly ME_INFO: "me-info";
|
|
32
|
+
readonly FRIENDS: "friends";
|
|
33
|
+
readonly GROUPS: "groups";
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoBH,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAQzE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAiB,GAAG,CAAC,GAAG,IAAI,CAYhG;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAUtE;AAGD,eAAO,MAAM,UAAU;;;;CAIb,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZaloX — File-based cache for cross-process data sharing
|
|
3
|
+
*
|
|
4
|
+
* Problem: Each `zca` CLI invocation is a separate process.
|
|
5
|
+
* zca-js login() creates a new Zalo session, invalidating the previous one.
|
|
6
|
+
* This kills any active WebSocket listener.
|
|
7
|
+
*
|
|
8
|
+
* Solution: Cache API responses to disk after the first login.
|
|
9
|
+
* Subsequent commands read from cache instead of logging in again.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { getConfigDir } from './config.js';
|
|
14
|
+
const CACHE_DIR_NAME = 'cache';
|
|
15
|
+
function getCacheDir(profile) {
|
|
16
|
+
const dir = join(getConfigDir(), CACHE_DIR_NAME, profile);
|
|
17
|
+
if (!existsSync(dir)) {
|
|
18
|
+
mkdirSync(dir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
return dir;
|
|
21
|
+
}
|
|
22
|
+
function getCachePath(profile, key) {
|
|
23
|
+
return join(getCacheDir(profile), `${key}.json`);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Write data to cache file
|
|
27
|
+
*/
|
|
28
|
+
export function writeCache(profile, key, data) {
|
|
29
|
+
const entry = {
|
|
30
|
+
data,
|
|
31
|
+
cachedAt: Date.now(),
|
|
32
|
+
profile,
|
|
33
|
+
};
|
|
34
|
+
const path = getCachePath(profile, key);
|
|
35
|
+
writeFileSync(path, JSON.stringify(entry, null, 2));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Read data from cache file
|
|
39
|
+
* @param maxAgeMs - Maximum age of cache in milliseconds (default: 1 hour)
|
|
40
|
+
* @returns cached data or null if cache miss/expired
|
|
41
|
+
*/
|
|
42
|
+
export function readCache(profile, key, maxAgeMs = 3600_000) {
|
|
43
|
+
const path = getCachePath(profile, key);
|
|
44
|
+
if (!existsSync(path))
|
|
45
|
+
return null;
|
|
46
|
+
try {
|
|
47
|
+
const entry = JSON.parse(readFileSync(path, 'utf-8'));
|
|
48
|
+
const age = Date.now() - entry.cachedAt;
|
|
49
|
+
if (age > maxAgeMs)
|
|
50
|
+
return null; // expired
|
|
51
|
+
return entry.data;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Read cache regardless of age (for offline mode)
|
|
59
|
+
*/
|
|
60
|
+
export function readCacheAny(profile, key) {
|
|
61
|
+
const path = getCachePath(profile, key);
|
|
62
|
+
if (!existsSync(path))
|
|
63
|
+
return null;
|
|
64
|
+
try {
|
|
65
|
+
const entry = JSON.parse(readFileSync(path, 'utf-8'));
|
|
66
|
+
return entry.data;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Cache keys
|
|
73
|
+
export const CACHE_KEYS = {
|
|
74
|
+
ME_INFO: 'me-info',
|
|
75
|
+
FRIENDS: 'friends',
|
|
76
|
+
GROUPS: 'groups',
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,SAAS,WAAW,CAAC,OAAe;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,OAAe,EAAE,GAAW;IAChD,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;AACnD,CAAC;AAQD;;GAEG;AACH,MAAM,UAAU,UAAU,CAAI,OAAe,EAAE,GAAW,EAAE,IAAO;IACjE,MAAM,KAAK,GAAkB;QAC3B,IAAI;QACJ,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;QACpB,OAAO;KACR,CAAC;IACF,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACxC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAI,OAAe,EAAE,GAAW,EAAE,WAAmB,QAAQ;IACpF,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,IAAI,CAAC;QACH,MAAM,KAAK,GAAkB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACrE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC;QACxC,IAAI,GAAG,GAAG,QAAQ;YAAE,OAAO,IAAI,CAAC,CAAC,UAAU;QAC3C,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAI,OAAe,EAAE,GAAW;IAC1D,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,IAAI,CAAC;QACH,MAAM,KAAK,GAAkB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACrE,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,aAAa;AACb,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;CACR,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZaloX — Config Management
|
|
3
|
+
* Config path: ~/.openclaw/zalox/ (persistent, survives container restarts)
|
|
4
|
+
* Fallback: ~/.config/zalox/ (legacy)
|
|
5
|
+
*/
|
|
6
|
+
import type { ZaloXConfig } from '../core/types.js';
|
|
7
|
+
export declare function getConfigDir(): string;
|
|
8
|
+
export declare function getProfilesDir(): string;
|
|
9
|
+
export declare function ensureConfigDir(): void;
|
|
10
|
+
export declare function getConfig(): ZaloXConfig;
|
|
11
|
+
export declare function saveConfig(config: ZaloXConfig): void;
|
|
12
|
+
export declare function setConfig<K extends keyof ZaloXConfig>(key: K, value: ZaloXConfig[K]): void;
|
|
13
|
+
export declare function getProfilePath(profileName: string): string;
|
|
14
|
+
export declare function profileExists(profileName: string): boolean;
|
|
15
|
+
export declare function listProfileFiles(): string[];
|
|
16
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAgCpD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,eAAe,IAAI,IAAI,CAOtC;AAID,wBAAgB,SAAS,IAAI,WAAW,CAYvC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGpD;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAI1F;AAID,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAM3C"}
|