paperkite 0.1.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.
Files changed (121) hide show
  1. package/README.md +81 -0
  2. package/data/flows.example.yml +65 -0
  3. package/data/settings.example.yml +13 -0
  4. package/dist/data/hooks/weekend-slot.d.ts +12 -0
  5. package/dist/data/hooks/weekend-slot.js +107 -0
  6. package/dist/data/hooks/weekend-slot.js.map +1 -0
  7. package/dist/packages/account-health/src/index.d.ts +8 -0
  8. package/dist/packages/account-health/src/index.js +37 -0
  9. package/dist/packages/account-health/src/index.js.map +1 -0
  10. package/dist/packages/archive/src/archiver.d.ts +98 -0
  11. package/dist/packages/archive/src/archiver.js +399 -0
  12. package/dist/packages/archive/src/archiver.js.map +1 -0
  13. package/dist/packages/archive/src/config.d.ts +22 -0
  14. package/dist/packages/archive/src/config.js +62 -0
  15. package/dist/packages/archive/src/config.js.map +1 -0
  16. package/dist/packages/archive/src/console/live.d.ts +24 -0
  17. package/dist/packages/archive/src/console/live.js +144 -0
  18. package/dist/packages/archive/src/console/live.js.map +1 -0
  19. package/dist/packages/archive/src/console/media.d.ts +66 -0
  20. package/dist/packages/archive/src/console/media.js +368 -0
  21. package/dist/packages/archive/src/console/media.js.map +1 -0
  22. package/dist/packages/archive/src/console/server.d.ts +12 -0
  23. package/dist/packages/archive/src/console/server.js +583 -0
  24. package/dist/packages/archive/src/console/server.js.map +1 -0
  25. package/dist/packages/archive/src/console/service.d.ts +13 -0
  26. package/dist/packages/archive/src/console/service.js +86 -0
  27. package/dist/packages/archive/src/console/service.js.map +1 -0
  28. package/dist/packages/archive/src/storage/index.d.ts +6 -0
  29. package/dist/packages/archive/src/storage/index.js +23 -0
  30. package/dist/packages/archive/src/storage/index.js.map +1 -0
  31. package/dist/packages/archive/src/storage/model.d.ts +296 -0
  32. package/dist/packages/archive/src/storage/model.js +151 -0
  33. package/dist/packages/archive/src/storage/model.js.map +1 -0
  34. package/dist/packages/archive/src/storage/postgres.d.ts +67 -0
  35. package/dist/packages/archive/src/storage/postgres.js +1021 -0
  36. package/dist/packages/archive/src/storage/postgres.js.map +1 -0
  37. package/dist/packages/archive/src/storage/sqlite.d.ts +59 -0
  38. package/dist/packages/archive/src/storage/sqlite.js +981 -0
  39. package/dist/packages/archive/src/storage/sqlite.js.map +1 -0
  40. package/dist/packages/notify-bark/src/index.d.ts +33 -0
  41. package/dist/packages/notify-bark/src/index.js +96 -0
  42. package/dist/packages/notify-bark/src/index.js.map +1 -0
  43. package/dist/packages/runtime-console/src/console/errors.d.ts +5 -0
  44. package/dist/packages/runtime-console/src/console/errors.js +11 -0
  45. package/dist/packages/runtime-console/src/console/errors.js.map +1 -0
  46. package/dist/packages/runtime-console/src/console/logs.d.ts +1 -0
  47. package/dist/packages/runtime-console/src/console/logs.js +27 -0
  48. package/dist/packages/runtime-console/src/console/logs.js.map +1 -0
  49. package/dist/packages/runtime-console/src/console/server.d.ts +6 -0
  50. package/dist/packages/runtime-console/src/console/server.js +182 -0
  51. package/dist/packages/runtime-console/src/console/server.js.map +1 -0
  52. package/dist/packages/runtime-console/src/index.d.ts +10 -0
  53. package/dist/packages/runtime-console/src/index.js +83 -0
  54. package/dist/packages/runtime-console/src/index.js.map +1 -0
  55. package/dist/src/app.d.ts +15 -0
  56. package/dist/src/app.js +34 -0
  57. package/dist/src/app.js.map +1 -0
  58. package/dist/src/cli.d.ts +2 -0
  59. package/dist/src/cli.js +250 -0
  60. package/dist/src/cli.js.map +1 -0
  61. package/dist/src/config/editor.d.ts +2 -0
  62. package/dist/src/config/editor.js +19 -0
  63. package/dist/src/config/editor.js.map +1 -0
  64. package/dist/src/config/loader.d.ts +6 -0
  65. package/dist/src/config/loader.js +188 -0
  66. package/dist/src/config/loader.js.map +1 -0
  67. package/dist/src/config/model.d.ts +71 -0
  68. package/dist/src/config/model.js +97 -0
  69. package/dist/src/config/model.js.map +1 -0
  70. package/dist/src/config/paths.d.ts +3 -0
  71. package/dist/src/config/paths.js +12 -0
  72. package/dist/src/config/paths.js.map +1 -0
  73. package/dist/src/config/settings.d.ts +19 -0
  74. package/dist/src/config/settings.js +44 -0
  75. package/dist/src/config/settings.js.map +1 -0
  76. package/dist/src/control/process-lock.d.ts +4 -0
  77. package/dist/src/control/process-lock.js +57 -0
  78. package/dist/src/control/process-lock.js.map +1 -0
  79. package/dist/src/control/socket.d.ts +14 -0
  80. package/dist/src/control/socket.js +131 -0
  81. package/dist/src/control/socket.js.map +1 -0
  82. package/dist/src/engine/hooks.d.ts +4 -0
  83. package/dist/src/engine/hooks.js +38 -0
  84. package/dist/src/engine/hooks.js.map +1 -0
  85. package/dist/src/engine/logger.d.ts +17 -0
  86. package/dist/src/engine/logger.js +78 -0
  87. package/dist/src/engine/logger.js.map +1 -0
  88. package/dist/src/engine/runtime.d.ts +78 -0
  89. package/dist/src/engine/runtime.js +799 -0
  90. package/dist/src/engine/runtime.js.map +1 -0
  91. package/dist/src/engine/scheduler.d.ts +9 -0
  92. package/dist/src/engine/scheduler.js +58 -0
  93. package/dist/src/engine/scheduler.js.map +1 -0
  94. package/dist/src/extensions/loader.d.ts +11 -0
  95. package/dist/src/extensions/loader.js +202 -0
  96. package/dist/src/extensions/loader.js.map +1 -0
  97. package/dist/src/extensions/manager.d.ts +1 -0
  98. package/dist/src/extensions/manager.js +121 -0
  99. package/dist/src/extensions/manager.js.map +1 -0
  100. package/dist/src/extensions/profile.d.ts +14 -0
  101. package/dist/src/extensions/profile.js +57 -0
  102. package/dist/src/extensions/profile.js.map +1 -0
  103. package/dist/src/extensions/registry.d.ts +19 -0
  104. package/dist/src/extensions/registry.js +62 -0
  105. package/dist/src/extensions/registry.js.map +1 -0
  106. package/dist/src/telegram/client.d.ts +20 -0
  107. package/dist/src/telegram/client.js +54 -0
  108. package/dist/src/telegram/client.js.map +1 -0
  109. package/dist/src/telegram/failure.d.ts +2 -0
  110. package/dist/src/telegram/failure.js +98 -0
  111. package/dist/src/telegram/failure.js.map +1 -0
  112. package/dist/src/telegram/login.d.ts +1 -0
  113. package/dist/src/telegram/login.js +31 -0
  114. package/dist/src/telegram/login.js.map +1 -0
  115. package/dist/src/telegram/pool.d.ts +47 -0
  116. package/dist/src/telegram/pool.js +300 -0
  117. package/dist/src/telegram/pool.js.map +1 -0
  118. package/dist/src/telegram/session-files.d.ts +4 -0
  119. package/dist/src/telegram/session-files.js +34 -0
  120. package/dist/src/telegram/session-files.js.map +1 -0
  121. package/package.json +62 -0
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # 纸鸢
2
+
3
+ 纸鸢是一个以 TypeScript 编写的 Telegram 自动化运行时。触发器、动作、定时任务与常驻服务统一写在一份 YAML 配置里,插件只通过能力名接入运行时。
4
+
5
+ ## 快速开始
6
+
7
+ ```bash
8
+ pnpm install
9
+ cp data/settings.example.yml data/settings.yml
10
+ cp data/flows.example.yml data/flows.yml
11
+ pnpm build
12
+ pnpm start init
13
+ pnpm start run
14
+ ```
15
+
16
+ 首次运行前先用 `paperkite session login <会话名>` 登录,在终端按提示输入电话号、验证码即可。凭据、会话、日志和数据库都已加入忽略规则,不应提交到仓库。
17
+
18
+ ## 框架
19
+
20
+ 运行时把自动化分成四类,统一写在 `data/flows.yml`:
21
+
22
+ | 类别 | 说明 |
23
+ | --- | --- |
24
+ | `triggers` | 事件驱动,收到消息、会话状态变化时执行动作 |
25
+ | `commands` | 手动命令,通过控制台或 CLI 触发 |
26
+ | `schedules` | 定时任务 |
27
+ | `services` | 常驻服务(Web 终端等) |
28
+
29
+ 动作统一为 `capability + session + config`:
30
+
31
+ ```yaml
32
+ run:
33
+ capability: messages.send
34
+ session: primary
35
+ config:
36
+ peer: "@someone"
37
+ text: "hello"
38
+ ```
39
+
40
+ 运行时只加载配置实际用到的能力。会话由运行时统一持有,插件只以会话名访问。动作文本支持 `{{event.text}}`、`{{event.senderId}}` 等路径模板,也兼容 `{text}`、`{chat}` 等简写。动作可以挂 `hook` 指向一个 TypeScript 模块,在执行前转换或跳过本次 config。
41
+
42
+ 重载会停止现有流、重读 flows.yml 并按新配置重启,进程与会话池不退出;settings.yml 仍需重启生效。CLI、Web 控制台等前端都通过同一份运行时控制契约取数、下发操作、订阅事件。
43
+
44
+ ## 插件
45
+
46
+ 插件是独立的 workspace 项目,有自己的 `package.json` 与 `paperkite.plugin` 声明。配置与用法见各插件包内的 README。
47
+
48
+ | 插件 | 能力 | 文档 |
49
+ | --- | --- | --- |
50
+ | `@paperkite/plugin-messages` | `messages.send` | [README](packages/messages/README.md) |
51
+ | `@paperkite/plugin-notify-bark` | `notify.bark` | [README](packages/notify-bark/README.md) |
52
+ | `@paperkite/plugin-messages-watch` | `messages.watch`、`messages.poll` | [README](packages/messages-watch/README.md) |
53
+ | `@paperkite/plugin-account-health` | `account.health` | [README](packages/account-health/README.md) |
54
+ | `@paperkite/plugin-archive` | `archive.sync`、`archive.console` | [README](packages/archive/README.md) |
55
+ | `@paperkite/plugin-process-run` | `process.run` | [README](packages/process-run/README.md) |
56
+ | `@paperkite/plugin-favorites-cleanup` | `favorites.cleanup` | [README](packages/favorites-cleanup/README.md) |
57
+ | `@paperkite/plugin-runtime-console` | `runtime.console` | [README](packages/runtime-console/README.md) |
58
+
59
+ `@paperkite/sdk` 是共享库,不属于插件,没有 `paperkite.plugin` 声明。
60
+
61
+ ### 插件安装
62
+
63
+ 内置插件(`paperkite.bundles`)随核心安装目录解析,默认可用;`plugin add` 可安装第三方插件,或安装同名包覆盖内置插件。
64
+
65
+ 插件管理用 profile 目录中的 `package.json` 保存依赖和启用清单:
66
+
67
+ ```bash
68
+ paperkite plugin --profile default add <npm-package>
69
+ paperkite plugin --profile default remove <npm-package>
70
+ paperkite plugin --profile default update <npm-package>
71
+ ```
72
+
73
+ `add`、`remove`、`update` 后面的参数由 pnpm 处理。只有带 `paperkite.plugin` 声明的依赖才会成为可加载插件。
74
+
75
+ ## 开发
76
+
77
+ ```bash
78
+ pnpm typecheck
79
+ pnpm test
80
+ pnpm build
81
+ ```
@@ -0,0 +1,65 @@
1
+ commands:
2
+ - id: send-test
3
+ title: 发送测试消息
4
+ run:
5
+ capability: messages.send
6
+ session: primary
7
+ config:
8
+ peer: "@example"
9
+ text: "纸鸢测试消息"
10
+
11
+ triggers:
12
+ - id: account-health
13
+ capability: account.health
14
+ config:
15
+ notifyOnRecovery: true
16
+ actions:
17
+ - capability: notify.bark
18
+ config:
19
+ key: replace-with-your-bark-key
20
+ title: 会话异常
21
+ body: "{{event.session}} {{event.state}}"
22
+
23
+ - id: important-message
24
+ capability: messages.watch
25
+ session: primary
26
+ config:
27
+ chats: ["@example"]
28
+ keywords: ["提醒"]
29
+ actions:
30
+ - capability: notify.bark
31
+ config:
32
+ key: replace-with-your-bark-key
33
+ title: 新消息
34
+ body: "{{event.text}}"
35
+
36
+ - id: important-message-secondary
37
+ capability: messages.watch
38
+ session: secondary
39
+ config:
40
+ chats: ["@example"]
41
+ keywords: ["提醒"]
42
+ actions:
43
+ - capability: notify.bark
44
+ config:
45
+ key: replace-with-your-bark-key
46
+ title: 新消息
47
+ body: "{{event.text}}"
48
+
49
+ schedules:
50
+ - id: archive-hourly
51
+ intervalSeconds: 3600
52
+ session: primary
53
+ run:
54
+ capability: archive.sync
55
+ config:
56
+ url: sqlite:data/archive.sqlite
57
+ chats: ["@example"]
58
+ maxMessages: 500
59
+
60
+ services:
61
+ - id: runtime-console
62
+ capability: runtime.console
63
+ config:
64
+ host: 127.0.0.1
65
+ port: 3378
@@ -0,0 +1,13 @@
1
+ telegram:
2
+ apiId: 123456
3
+ apiHash: replace-with-your-api-hash
4
+ sessionsDir: accounts
5
+ sessionGuard:
6
+ windowMs: 60000
7
+ threshold: 5
8
+ backoffMinMs: 30000
9
+ backoffMaxMs: 1800000
10
+
11
+ logging:
12
+ level: info
13
+ directory: logs
@@ -0,0 +1,12 @@
1
+ interface HookInput {
2
+ readonly config: unknown;
3
+ readonly emission?: {
4
+ readonly event?: unknown;
5
+ };
6
+ }
7
+ interface HookResult {
8
+ readonly config?: unknown;
9
+ readonly skip?: boolean;
10
+ }
11
+ export default function weekendSlot({ config, emission }: HookInput): HookResult | undefined;
12
+ export {};
@@ -0,0 +1,107 @@
1
+ const DAY_KEYS = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
2
+ const DAY_ALIASES = {
3
+ 周一: "周一",
4
+ 星期一: "周一",
5
+ 礼拜一: "周一",
6
+ 周二: "周二",
7
+ 星期二: "周二",
8
+ 礼拜二: "周二",
9
+ 周三: "周三",
10
+ 星期三: "周三",
11
+ 礼拜三: "周三",
12
+ 周四: "周四",
13
+ 星期四: "周四",
14
+ 礼拜四: "周四",
15
+ 周五: "周五",
16
+ 星期五: "周五",
17
+ 礼拜五: "周五",
18
+ 周六: "周六",
19
+ 星期六: "周六",
20
+ 礼拜六: "周六",
21
+ 周日: "周日",
22
+ 星期日: "周日",
23
+ 星期天: "周日",
24
+ 周天: "周日",
25
+ 礼拜日: "周日",
26
+ 礼拜天: "周日"
27
+ };
28
+ const timePattern = /\d{1,2}(?:[.:]\d{1,2})?/g;
29
+ export default function weekendSlot({ config, emission }) {
30
+ if (!isRecord(config))
31
+ return undefined;
32
+ const event = isRecord(emission?.event) ? emission.event : undefined;
33
+ const source = typeof event?.text === "string" ? event.text : "";
34
+ if (!source)
35
+ return undefined;
36
+ const day = findSlot(source, enabledDays(config.days));
37
+ if (!day)
38
+ return { skip: true };
39
+ const text = config.text;
40
+ if (Array.isArray(text)) {
41
+ return { config: { text: text.map((value) => inject(String(value), day)) } };
42
+ }
43
+ if (typeof text === "string")
44
+ return { config: { text: inject(text, day) } };
45
+ return undefined;
46
+ }
47
+ function enabledDays(days) {
48
+ if (!Array.isArray(days))
49
+ return new Set(DAY_KEYS);
50
+ const enabled = new Set();
51
+ for (const value of days) {
52
+ const day = toDay(value);
53
+ if (day)
54
+ enabled.add(day);
55
+ }
56
+ return enabled.size > 0 ? enabled : new Set(DAY_KEYS);
57
+ }
58
+ function toDay(value) {
59
+ if (typeof value === "string")
60
+ return DAY_ALIASES[value];
61
+ if (typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 7) {
62
+ return DAY_KEYS[value - 1];
63
+ }
64
+ return undefined;
65
+ }
66
+ function findSlot(source, enabled) {
67
+ for (const line of source.split(/\r?\n/)) {
68
+ const day = lineDay(line, enabled);
69
+ if (!day)
70
+ continue;
71
+ const start = firstSlotStart(line);
72
+ if (start?.startsWith("3"))
73
+ return day;
74
+ }
75
+ return undefined;
76
+ }
77
+ function lineDay(line, enabled) {
78
+ let found;
79
+ for (const [name, day] of Object.entries(DAY_ALIASES)) {
80
+ const position = line.indexOf(name);
81
+ if (position < 0 || !enabled.has(day))
82
+ continue;
83
+ if (found && position >= found.position)
84
+ continue;
85
+ found = { position, day };
86
+ }
87
+ return found?.day;
88
+ }
89
+ function firstSlotStart(line) {
90
+ timePattern.lastIndex = 0;
91
+ let match;
92
+ while ((match = timePattern.exec(line))) {
93
+ const token = match[0] ?? "";
94
+ const suffix = line[match.index + token.length];
95
+ if (suffix === "号" || suffix === "日" || suffix === "月")
96
+ continue;
97
+ return token;
98
+ }
99
+ return undefined;
100
+ }
101
+ function inject(value, day) {
102
+ return value.replace("帮我约", `帮我约${day}`);
103
+ }
104
+ function isRecord(value) {
105
+ return typeof value === "object" && value !== null && !Array.isArray(value);
106
+ }
107
+ //# sourceMappingURL=weekend-slot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weekend-slot.js","sourceRoot":"","sources":["../../../data/hooks/weekend-slot.ts"],"names":[],"mappings":"AAYA,MAAM,QAAQ,GAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAE/E,MAAM,WAAW,GAA2B;IAC1C,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;CACV,CAAC;AACF,MAAM,WAAW,GAAG,0BAA0B,CAAC;AAE/C,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAa;IACjE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACrE,MAAM,MAAM,GAAG,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAE9B,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;IAC/E,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IAC7E,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,WAAW,CAAC,IAAa;IAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,GAAG;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,KAAK,CAAC,KAAc;IAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;IACzD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACrF,OAAO,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc,EAAE,OAA4B;IAC5D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;IACzC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,OAA4B;IACzD,IAAI,KAAoD,CAAC;IACzD,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,QAAQ,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAChD,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,CAAC,QAAQ;YAAE,SAAS;QAClD,KAAK,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,EAAE,GAAG,CAAC;AACpB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,WAAW,CAAC,SAAS,GAAG,CAAC,CAAC;IAC1B,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;YAAE,SAAS;QACjE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,MAAM,CAAC,KAAa,EAAE,GAAW;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { Trigger } from "@paperkite/sdk";
2
+ interface HealthConfig {
3
+ readonly notifyOnRecovery?: boolean;
4
+ }
5
+ export declare class SessionHealthTrigger extends Trigger<HealthConfig> {
6
+ run(): Promise<void>;
7
+ }
8
+ export {};
@@ -0,0 +1,37 @@
1
+ import { Trigger } from "@paperkite/sdk";
2
+ export class SessionHealthTrigger extends Trigger {
3
+ async run() {
4
+ if (!this.control)
5
+ throw new Error("session health watcher needs the runtime control contract");
6
+ const notifyRecovery = this.config.notifyOnRecovery === true;
7
+ const notify = (name, state, reason) => {
8
+ return this.emit({ session: name, state, reason });
9
+ };
10
+ for (const info of this.control.snapshot.sessions) {
11
+ if (info.state !== "connected" && info.state !== "starting") {
12
+ await notify(info.name, info.state, info.reason);
13
+ }
14
+ }
15
+ const unsubscribe = this.control.subscribe((event) => {
16
+ if (event.type !== "session.state" || event.state === "starting")
17
+ return;
18
+ if (event.state === "connected" && !notifyRecovery)
19
+ return;
20
+ void notify(event.name, event.state, event.reason).catch((error) => {
21
+ this.context.logger.error("session health watcher notification failed", error);
22
+ });
23
+ });
24
+ try {
25
+ await waitForAbort(this.signal);
26
+ }
27
+ finally {
28
+ unsubscribe();
29
+ }
30
+ }
31
+ }
32
+ async function waitForAbort(signal) {
33
+ if (signal.aborted)
34
+ return;
35
+ await new Promise((resolve) => signal.addEventListener("abort", () => resolve(), { once: true }));
36
+ }
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/account-health/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAqB,MAAM,gBAAgB,CAAC;AAM5D,MAAM,OAAO,oBAAqB,SAAQ,OAAqB;IAC7D,KAAK,CAAC,GAAG;QACP,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAChG,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,KAAK,IAAI,CAAC;QAC7D,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAmB,EAAE,MAA0B,EAAiB,EAAE;YAC9F,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC;QAEF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;YAClD,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;gBAC5D,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;YACnD,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,KAAK,CAAC,KAAK,KAAK,UAAU;gBAAE,OAAO;YACzE,IAAI,KAAK,CAAC,KAAK,KAAK,WAAW,IAAI,CAAC,cAAc;gBAAE,OAAO;YAC3D,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC1E,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,EAAE,KAAK,CAAC,CAAC;YACjF,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,WAAW,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;CACF;AAED,KAAK,UAAU,YAAY,CAAC,MAAmB;IAC7C,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO;IAC3B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC1G,CAAC"}
@@ -0,0 +1,98 @@
1
+ import type { RuntimeLogger } from "@paperkite/sdk";
2
+ import type { ArchiveStore, MessageEntity } from "./storage/index.js";
3
+ export interface TelegramMessage {
4
+ readonly id: number;
5
+ readonly date: number;
6
+ readonly text?: string;
7
+ readonly rawText?: string;
8
+ readonly message?: string;
9
+ readonly entities?: readonly unknown[];
10
+ readonly media?: unknown;
11
+ readonly sender?: unknown;
12
+ readonly senderId?: unknown;
13
+ readonly replyToMessageId?: number;
14
+ readonly replyTo?: {
15
+ readonly replyToMessageId?: number;
16
+ readonly replyToTopId?: number;
17
+ };
18
+ readonly forward?: {
19
+ readonly fromId?: unknown;
20
+ readonly fromName?: string;
21
+ };
22
+ readonly fwdFrom?: {
23
+ readonly fromId?: unknown;
24
+ readonly fromName?: string;
25
+ };
26
+ readonly groupedId?: unknown;
27
+ }
28
+ export interface DialogEntry {
29
+ readonly title?: string;
30
+ readonly entity?: unknown;
31
+ }
32
+ /** GramJS downloadMedia 的缩略图参数:sizeType 字符串("s"/"m"…)或 PhotoSize/VideoSize 实例。 */
33
+ export type ThumbParam = number | string | unknown;
34
+ export interface ArchiveClient {
35
+ getEntity(identifier: string | number): Promise<unknown>;
36
+ iterDialogs(): AsyncIterable<DialogEntry>;
37
+ iterMessages(entity: unknown, options: {
38
+ limit: number;
39
+ maxId: number;
40
+ }): AsyncIterable<TelegramMessage>;
41
+ getMessages(entity: unknown, options: {
42
+ ids: readonly number[];
43
+ }): Promise<readonly (TelegramMessage | undefined)[]>;
44
+ downloadMedia(message: TelegramMessage, options?: {
45
+ outputFile?: string;
46
+ thumb?: ThumbParam;
47
+ }): Promise<Buffer | string | undefined>;
48
+ /** 按字节区间逐块产出媒体;未提供时控制台以 gramjs 原生迭代回退。 */
49
+ iterMediaChunks?(media: unknown, options: {
50
+ offset: number;
51
+ limit: number;
52
+ }): AsyncIterable<Buffer> | undefined;
53
+ }
54
+ export interface ChatInfo {
55
+ readonly chatId: string;
56
+ readonly title?: string;
57
+ readonly username?: string;
58
+ readonly type: "channel" | "group" | "user";
59
+ readonly description?: string;
60
+ readonly membersCount?: number;
61
+ }
62
+ export interface ArchiveRunOptions {
63
+ readonly daysBack?: number;
64
+ readonly maxMessages?: number;
65
+ readonly resume?: boolean;
66
+ readonly downloadMedia?: boolean;
67
+ }
68
+ export interface ArchiveResult {
69
+ readonly messages: number;
70
+ readonly media: number;
71
+ readonly skipped: number;
72
+ }
73
+ export interface ArchiverDependencies {
74
+ readonly store: ArchiveStore;
75
+ readonly mediaDir: string;
76
+ readonly downloadMedia: boolean;
77
+ readonly batchSize: number;
78
+ readonly shouldStop: () => boolean;
79
+ readonly submit: <T>(operation: (client: ArchiveClient) => T | Promise<T>) => Promise<T>;
80
+ readonly chatIdOf: (entity: unknown) => string;
81
+ readonly logger: RuntimeLogger;
82
+ }
83
+ export declare class MessageArchiver {
84
+ private readonly deps;
85
+ constructor(deps: ArchiverDependencies);
86
+ findChat(identifier: string | number): Promise<ChatInfo | undefined>;
87
+ saveChatMessages(chatIdentifier: string | number, options?: ArchiveRunOptions): Promise<ArchiveResult>;
88
+ private resolveEntity;
89
+ private planSyncWindow;
90
+ private runSyncWindow;
91
+ private sweep;
92
+ private fetchPageOnHost;
93
+ private commitPage;
94
+ private downloadNewMedia;
95
+ private downloadMediaOnHost;
96
+ }
97
+ /** 消息实体归一化:与 Telegram 原生对齐(offset/length 为 UTF-16 码元),链接实体保留目标 URL。 */
98
+ export declare function normalizeEntities(entities: readonly unknown[] | undefined): readonly MessageEntity[];