@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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +185 -0
  3. package/dist/cli/commands/admin.d.ts +17 -0
  4. package/dist/cli/commands/admin.d.ts.map +1 -0
  5. package/dist/cli/commands/admin.js +359 -0
  6. package/dist/cli/commands/admin.js.map +1 -0
  7. package/dist/cli/commands/auth.d.ts +3 -0
  8. package/dist/cli/commands/auth.d.ts.map +1 -0
  9. package/dist/cli/commands/auth.js +88 -0
  10. package/dist/cli/commands/auth.js.map +1 -0
  11. package/dist/cli/commands/autoreply.d.ts +12 -0
  12. package/dist/cli/commands/autoreply.d.ts.map +1 -0
  13. package/dist/cli/commands/autoreply.js +162 -0
  14. package/dist/cli/commands/autoreply.js.map +1 -0
  15. package/dist/cli/commands/bulk.d.ts +9 -0
  16. package/dist/cli/commands/bulk.d.ts.map +1 -0
  17. package/dist/cli/commands/bulk.js +169 -0
  18. package/dist/cli/commands/bulk.js.map +1 -0
  19. package/dist/cli/commands/config.d.ts +14 -0
  20. package/dist/cli/commands/config.d.ts.map +1 -0
  21. package/dist/cli/commands/config.js +122 -0
  22. package/dist/cli/commands/config.js.map +1 -0
  23. package/dist/cli/commands/conv.d.ts +3 -0
  24. package/dist/cli/commands/conv.d.ts.map +1 -0
  25. package/dist/cli/commands/conv.js +229 -0
  26. package/dist/cli/commands/conv.js.map +1 -0
  27. package/dist/cli/commands/daemon.d.ts +13 -0
  28. package/dist/cli/commands/daemon.d.ts.map +1 -0
  29. package/dist/cli/commands/daemon.js +102 -0
  30. package/dist/cli/commands/daemon.js.map +1 -0
  31. package/dist/cli/commands/export.d.ts +10 -0
  32. package/dist/cli/commands/export.d.ts.map +1 -0
  33. package/dist/cli/commands/export.js +98 -0
  34. package/dist/cli/commands/export.js.map +1 -0
  35. package/dist/cli/commands/friend.d.ts +13 -0
  36. package/dist/cli/commands/friend.d.ts.map +1 -0
  37. package/dist/cli/commands/friend.js +337 -0
  38. package/dist/cli/commands/friend.js.map +1 -0
  39. package/dist/cli/commands/group-settings.d.ts +11 -0
  40. package/dist/cli/commands/group-settings.d.ts.map +1 -0
  41. package/dist/cli/commands/group-settings.js +154 -0
  42. package/dist/cli/commands/group-settings.js.map +1 -0
  43. package/dist/cli/commands/group.d.ts +14 -0
  44. package/dist/cli/commands/group.d.ts.map +1 -0
  45. package/dist/cli/commands/group.js +365 -0
  46. package/dist/cli/commands/group.js.map +1 -0
  47. package/dist/cli/commands/license.d.ts +13 -0
  48. package/dist/cli/commands/license.d.ts.map +1 -0
  49. package/dist/cli/commands/license.js +218 -0
  50. package/dist/cli/commands/license.js.map +1 -0
  51. package/dist/cli/commands/listen.d.ts +3 -0
  52. package/dist/cli/commands/listen.d.ts.map +1 -0
  53. package/dist/cli/commands/listen.js +177 -0
  54. package/dist/cli/commands/listen.js.map +1 -0
  55. package/dist/cli/commands/me.d.ts +9 -0
  56. package/dist/cli/commands/me.d.ts.map +1 -0
  57. package/dist/cli/commands/me.js +135 -0
  58. package/dist/cli/commands/me.js.map +1 -0
  59. package/dist/cli/commands/msg.d.ts +11 -0
  60. package/dist/cli/commands/msg.d.ts.map +1 -0
  61. package/dist/cli/commands/msg.js +255 -0
  62. package/dist/cli/commands/msg.js.map +1 -0
  63. package/dist/cli/commands/profile.d.ts +3 -0
  64. package/dist/cli/commands/profile.d.ts.map +1 -0
  65. package/dist/cli/commands/profile.js +50 -0
  66. package/dist/cli/commands/profile.js.map +1 -0
  67. package/dist/cli/commands/schedule.d.ts +12 -0
  68. package/dist/cli/commands/schedule.d.ts.map +1 -0
  69. package/dist/cli/commands/schedule.js +175 -0
  70. package/dist/cli/commands/schedule.js.map +1 -0
  71. package/dist/cli/commands/serve.d.ts +3 -0
  72. package/dist/cli/commands/serve.d.ts.map +1 -0
  73. package/dist/cli/commands/serve.js +87 -0
  74. package/dist/cli/commands/serve.js.map +1 -0
  75. package/dist/cli/commands/template.d.ts +12 -0
  76. package/dist/cli/commands/template.d.ts.map +1 -0
  77. package/dist/cli/commands/template.js +163 -0
  78. package/dist/cli/commands/template.js.map +1 -0
  79. package/dist/cli/index.d.ts +3 -0
  80. package/dist/cli/index.d.ts.map +1 -0
  81. package/dist/cli/index.js +116 -0
  82. package/dist/cli/index.js.map +1 -0
  83. package/dist/cli/output.d.ts +63 -0
  84. package/dist/cli/output.d.ts.map +1 -0
  85. package/dist/cli/output.js +144 -0
  86. package/dist/cli/output.js.map +1 -0
  87. package/dist/core/autoreply.d.ts +57 -0
  88. package/dist/core/autoreply.d.ts.map +1 -0
  89. package/dist/core/autoreply.js +159 -0
  90. package/dist/core/autoreply.js.map +1 -0
  91. package/dist/core/bulk.d.ts +36 -0
  92. package/dist/core/bulk.d.ts.map +1 -0
  93. package/dist/core/bulk.js +117 -0
  94. package/dist/core/bulk.js.map +1 -0
  95. package/dist/core/client.d.ts +8 -0
  96. package/dist/core/client.d.ts.map +1 -0
  97. package/dist/core/client.js +91 -0
  98. package/dist/core/client.js.map +1 -0
  99. package/dist/core/daemon.d.ts +30 -0
  100. package/dist/core/daemon.d.ts.map +1 -0
  101. package/dist/core/daemon.js +213 -0
  102. package/dist/core/daemon.js.map +1 -0
  103. package/dist/core/dm-commands.d.ts +41 -0
  104. package/dist/core/dm-commands.d.ts.map +1 -0
  105. package/dist/core/dm-commands.js +313 -0
  106. package/dist/core/dm-commands.js.map +1 -0
  107. package/dist/core/export.d.ts +20 -0
  108. package/dist/core/export.d.ts.map +1 -0
  109. package/dist/core/export.js +92 -0
  110. package/dist/core/export.js.map +1 -0
  111. package/dist/core/gate.d.ts +39 -0
  112. package/dist/core/gate.d.ts.map +1 -0
  113. package/dist/core/gate.js +75 -0
  114. package/dist/core/gate.js.map +1 -0
  115. package/dist/core/group-settings.d.ts +35 -0
  116. package/dist/core/group-settings.d.ts.map +1 -0
  117. package/dist/core/group-settings.js +70 -0
  118. package/dist/core/group-settings.js.map +1 -0
  119. package/dist/core/index.d.ts +22 -0
  120. package/dist/core/index.d.ts.map +1 -0
  121. package/dist/core/index.js +12 -0
  122. package/dist/core/index.js.map +1 -0
  123. package/dist/core/license.d.ts +103 -0
  124. package/dist/core/license.d.ts.map +1 -0
  125. package/dist/core/license.js +444 -0
  126. package/dist/core/license.js.map +1 -0
  127. package/dist/core/scheduler.d.ts +45 -0
  128. package/dist/core/scheduler.d.ts.map +1 -0
  129. package/dist/core/scheduler.js +203 -0
  130. package/dist/core/scheduler.js.map +1 -0
  131. package/dist/core/templates.d.ts +35 -0
  132. package/dist/core/templates.d.ts.map +1 -0
  133. package/dist/core/templates.js +107 -0
  134. package/dist/core/templates.js.map +1 -0
  135. package/dist/core/types.d.ts +57 -0
  136. package/dist/core/types.d.ts.map +1 -0
  137. package/dist/core/types.js +10 -0
  138. package/dist/core/types.js.map +1 -0
  139. package/dist/server/api.d.ts +2 -0
  140. package/dist/server/api.d.ts.map +1 -0
  141. package/dist/server/api.js +79 -0
  142. package/dist/server/api.js.map +1 -0
  143. package/dist/server/index.d.ts +16 -0
  144. package/dist/server/index.d.ts.map +1 -0
  145. package/dist/server/index.js +48 -0
  146. package/dist/server/index.js.map +1 -0
  147. package/dist/server/license-api.d.ts +55 -0
  148. package/dist/server/license-api.d.ts.map +1 -0
  149. package/dist/server/license-api.js +496 -0
  150. package/dist/server/license-api.js.map +1 -0
  151. package/dist/server/middleware.d.ts +18 -0
  152. package/dist/server/middleware.d.ts.map +1 -0
  153. package/dist/server/middleware.js +92 -0
  154. package/dist/server/middleware.js.map +1 -0
  155. package/dist/server/webhook.d.ts +10 -0
  156. package/dist/server/webhook.d.ts.map +1 -0
  157. package/dist/server/webhook.js +53 -0
  158. package/dist/server/webhook.js.map +1 -0
  159. package/dist/server/ws.d.ts +66 -0
  160. package/dist/server/ws.d.ts.map +1 -0
  161. package/dist/server/ws.js +203 -0
  162. package/dist/server/ws.js.map +1 -0
  163. package/dist/utils/cache.d.ts +35 -0
  164. package/dist/utils/cache.d.ts.map +1 -0
  165. package/dist/utils/cache.js +78 -0
  166. package/dist/utils/cache.js.map +1 -0
  167. package/dist/utils/config.d.ts +16 -0
  168. package/dist/utils/config.d.ts.map +1 -0
  169. package/dist/utils/config.js +88 -0
  170. package/dist/utils/config.js.map +1 -0
  171. package/dist/utils/logger.d.ts +17 -0
  172. package/dist/utils/logger.d.ts.map +1 -0
  173. package/dist/utils/logger.js +51 -0
  174. package/dist/utils/logger.js.map +1 -0
  175. 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,10 @@
1
+ import type { API } from 'zca-js';
2
+ export declare class WebhookManager {
3
+ private api;
4
+ private url;
5
+ private secret?;
6
+ constructor(api: API, url: string, secret?: string);
7
+ start(): void;
8
+ private forward;
9
+ }
10
+ //# sourceMappingURL=webhook.d.ts.map
@@ -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"}