@zhin.js/plugin-rss 3.0.4 → 3.0.6

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.
@@ -0,0 +1,58 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineCommand } from '@zhin.js/command';
3
+ import { extractChannelInfo } from "../../lib/channel.js";
4
+ import { getRssSeen, getRssSubs } from "../../lib/db-store.js";
5
+ import { fetchFeed, resolveRssConfig } from "../../lib/feed.js";
6
+ import { markItemsSeen } from "../../lib/poll.js";
7
+ export default defineCommand({
8
+ description: '订阅一个 RSS/Atom 源',
9
+ async execute({ params, config, input }) {
10
+ const Subs = getRssSubs();
11
+ if (!Subs)
12
+ return 'RSS 数据库尚未就绪,请稍后重试';
13
+ const url = String(params.url ?? '').trim();
14
+ if (!url)
15
+ return '请提供 RSS 源地址,格式:rss-add <URL>';
16
+ if (!/^https?:\/\//i.test(url))
17
+ return '请提供有效的 HTTP/HTTPS 地址';
18
+ const channel = extractChannelInfo(input);
19
+ const cfg = resolveRssConfig(config);
20
+ const existing = await Subs.select().where({
21
+ url,
22
+ adapter_name: channel.adapterName,
23
+ channel_type: channel.channelType,
24
+ channel_id: channel.channelId,
25
+ });
26
+ if (existing.length > 0)
27
+ return '当前会话已订阅该源,无需重复添加';
28
+ const currentSubs = await Subs.select().where({
29
+ adapter_name: channel.adapterName,
30
+ channel_type: channel.channelType,
31
+ channel_id: channel.channelId,
32
+ });
33
+ if (currentSubs.length >= cfg.maxPerGroup) {
34
+ return `当前会话订阅数已达上限 (${cfg.maxPerGroup}),请先取消一些`;
35
+ }
36
+ let feedTitle = '';
37
+ try {
38
+ const { title, items } = await fetchFeed(url, cfg.timeout);
39
+ feedTitle = title;
40
+ await markItemsSeen(url, items);
41
+ }
42
+ catch (e) {
43
+ return `无法解析该地址: ${e.message}\n请确认是有效的 RSS/Atom 源`;
44
+ }
45
+ await Subs.insert({
46
+ url,
47
+ feed_title: feedTitle,
48
+ adapter_name: channel.adapterName,
49
+ endpoint_id: channel.endpointId,
50
+ channel_type: channel.channelType,
51
+ channel_id: channel.channelId,
52
+ creator_id: channel.senderId,
53
+ creator_name: channel.senderName,
54
+ created_at: new Date().toISOString(),
55
+ });
56
+ return `订阅成功!\n源: ${feedTitle || url}\n新内容将在轮询时推送到本会话(需 OutboundHost)`;
57
+ },
58
+ });
@@ -0,0 +1,41 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineCommand } from '@zhin.js/command';
3
+ import { extractChannelInfo } from "../../lib/channel.js";
4
+ import { getRssSubs } from "../../lib/db-store.js";
5
+ import { resolveRssConfig } from "../../lib/feed.js";
6
+ import { checkSubscriptions } from "../../lib/poll.js";
7
+ export default defineCommand({
8
+ description: '手动触发检查 RSS 更新',
9
+ async execute({ params, config, input }) {
10
+ const Subs = getRssSubs();
11
+ if (!Subs)
12
+ return 'RSS 数据库尚未就绪';
13
+ const channel = extractChannelInfo(input);
14
+ const cfg = resolveRssConfig(config);
15
+ const targetUrl = String(params.url ?? '').trim();
16
+ let urls;
17
+ if (targetUrl) {
18
+ const rows = await Subs.select().where({
19
+ url: targetUrl,
20
+ adapter_name: channel.adapterName,
21
+ channel_type: channel.channelType,
22
+ channel_id: channel.channelId,
23
+ });
24
+ if (rows.length === 0)
25
+ return '当前会话未订阅该源';
26
+ urls = [targetUrl];
27
+ }
28
+ else {
29
+ const rows = await Subs.select().where({
30
+ adapter_name: channel.adapterName,
31
+ channel_type: channel.channelType,
32
+ channel_id: channel.channelId,
33
+ });
34
+ if (rows.length === 0)
35
+ return '当前会话没有任何订阅';
36
+ urls = [...new Set(rows.map((r) => String(r.url ?? '')).filter(Boolean))];
37
+ }
38
+ const result = await checkSubscriptions({ urls, config: cfg });
39
+ return result.text;
40
+ },
41
+ });
@@ -0,0 +1,28 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineCommand } from '@zhin.js/command';
3
+ import { extractChannelInfo } from "../lib/channel.js";
4
+ import { getRssSubs } from "../lib/db-store.js";
5
+ import { resolveRssConfig } from "../lib/feed.js";
6
+ export default defineCommand({
7
+ description: '查看当前会话的所有 RSS 订阅',
8
+ async execute({ config, input }) {
9
+ const Subs = getRssSubs();
10
+ if (!Subs)
11
+ return 'RSS 数据库尚未就绪';
12
+ const channel = extractChannelInfo(input);
13
+ const cfg = resolveRssConfig(config);
14
+ const rows = await Subs.select().where({
15
+ adapter_name: channel.adapterName,
16
+ channel_type: channel.channelType,
17
+ channel_id: channel.channelId,
18
+ });
19
+ if (rows.length === 0) {
20
+ return '当前会话没有订阅任何 RSS 源\n使用 rss-add <URL> 添加订阅';
21
+ }
22
+ const lines = rows.map((r, i) => {
23
+ const title = String(r.feed_title || '(未知标题)');
24
+ return `${i + 1}. ${title}\n ${String(r.url ?? '')}`;
25
+ });
26
+ return `当前订阅 (${rows.length}/${cfg.maxPerGroup}):\n${lines.join('\n')}`;
27
+ },
28
+ });
@@ -0,0 +1,21 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineCommand } from '@zhin.js/command';
3
+ import { fetchFeed, formatFeedPreview, resolveRssConfig } from "../../lib/feed.js";
4
+ export default defineCommand({
5
+ description: '预览一个 RSS 源的最新内容(不订阅)',
6
+ async execute({ params, config }) {
7
+ const url = String(params.url ?? '').trim();
8
+ if (!url)
9
+ return '请提供 RSS 源地址';
10
+ if (!/^https?:\/\//i.test(url))
11
+ return '请提供有效的 HTTP/HTTPS 地址';
12
+ const cfg = resolveRssConfig(config);
13
+ try {
14
+ const { title, items } = await fetchFeed(url, cfg.timeout);
15
+ return formatFeedPreview(title, items);
16
+ }
17
+ catch (e) {
18
+ return `解析失败: ${e.message}\n请确认是有效的 RSS/Atom 地址`;
19
+ }
20
+ },
21
+ });
@@ -0,0 +1,33 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineCommand } from '@zhin.js/command';
3
+ import { extractChannelInfo } from "../../lib/channel.js";
4
+ import { getRssSubs } from "../../lib/db-store.js";
5
+ export default defineCommand({
6
+ description: '取消一个 RSS 订阅',
7
+ async execute({ params, input }) {
8
+ const Subs = getRssSubs();
9
+ if (!Subs)
10
+ return 'RSS 数据库尚未就绪';
11
+ const url = String(params.url ?? '').trim();
12
+ if (!url)
13
+ return '请提供要取消的 RSS 源地址';
14
+ const channel = extractChannelInfo(input);
15
+ const rows = await Subs.select().where({
16
+ url,
17
+ adapter_name: channel.adapterName,
18
+ channel_type: channel.channelType,
19
+ channel_id: channel.channelId,
20
+ });
21
+ if (rows.length === 0)
22
+ return '未找到该订阅';
23
+ const row = rows[0];
24
+ // 表结构没有 id 列,删除必须按业务键匹配(与上面的 select 条件一致)。
25
+ await Subs.delete().where({
26
+ url,
27
+ adapter_name: channel.adapterName,
28
+ channel_type: channel.channelType,
29
+ channel_id: channel.channelId,
30
+ });
31
+ return `已取消订阅: ${String(row.feed_title || url)}`;
32
+ },
33
+ });
@@ -23,7 +23,13 @@ export default defineCommand<RssConfig>({
23
23
  if (rows.length === 0) return '未找到该订阅';
24
24
 
25
25
  const row = rows[0]!;
26
- await Subs.delete().where({ id: row.id });
26
+ // 表结构没有 id 列,删除必须按业务键匹配(与上面的 select 条件一致)。
27
+ await Subs.delete().where({
28
+ url,
29
+ adapter_name: channel.adapterName,
30
+ channel_type: channel.channelType,
31
+ channel_id: channel.channelId,
32
+ });
27
33
  return `已取消订阅: ${String(row.feed_title || url)}`;
28
34
  },
29
35
  });
package/lib/db-store.d.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  export { createInMemoryRssDb, RSS_SEEN_TABLE, RSS_SUBS_TABLE, type RssMemoryDb, type RssModel, } from './memory-store.js';
2
+ import { type Dispose, type GenerationStoreContext } from '@zhin.js/plugin-runtime';
2
3
  import { type RssMemoryDb, type RssModel } from './memory-store.js';
4
+ /**
5
+ * Generation-owned database binding used by Plugin Runtime setup().
6
+ * Auto-unregisters when the generation lifecycle disposes, so no stale
7
+ * reference to the previous generation's host survives a reload.
8
+ */
9
+ export declare function provideRssDb(context: GenerationStoreContext, db: RssMemoryDb): Dispose;
3
10
  export declare function ensureRssMemoryDb(): RssMemoryDb;
4
11
  export declare function getRssDb(): RssMemoryDb | null;
5
12
  export declare function setRssDb(db: RssMemoryDb | null): void;
@@ -1 +1 @@
1
- {"version":3,"file":"db-store.d.ts","sourceRoot":"","sources":["../src/db-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,mBAAmB,CAAC;AAI3B,wBAAgB,iBAAiB,IAAI,WAAW,CAG/C;AAED,wBAAgB,QAAQ,IAAI,WAAW,GAAG,IAAI,CAE7C;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAErD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,UAAU,IAAI,QAAQ,GAAG,IAAI,CAE5C;AAED,wBAAgB,UAAU,IAAI,QAAQ,GAAG,IAAI,CAE5C"}
1
+ {"version":3,"file":"db-store.d.ts","sourceRoot":"","sources":["../src/db-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAyB,KAAK,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC3G,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,mBAAmB,CAAC;AAO3B;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,sBAAsB,EAAE,EAAE,EAAE,WAAW,GAAG,OAAO,CAEtF;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAK/C;AAED,wBAAgB,QAAQ,IAAI,WAAW,GAAG,IAAI,CAE7C;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAErD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAIjC;AAED,wBAAgB,UAAU,IAAI,QAAQ,GAAG,IAAI,CAE5C;AAED,wBAAgB,UAAU,IAAI,QAAQ,GAAG,IAAI,CAE5C"}
package/lib/db-store.js CHANGED
@@ -1,10 +1,24 @@
1
1
  export { createInMemoryRssDb, RSS_SEEN_TABLE, RSS_SUBS_TABLE, } from './memory-store.js';
2
+ import { createGenerationStore } from '@zhin.js/plugin-runtime';
2
3
  import { createInMemoryRssDb, RSS_SEEN_TABLE, RSS_SUBS_TABLE, } from './memory-store.js';
4
+ const rssDbStore = createGenerationStore('rss/db');
3
5
  let _db = null;
6
+ let _memoryDb = null;
7
+ /**
8
+ * Generation-owned database binding used by Plugin Runtime setup().
9
+ * Auto-unregisters when the generation lifecycle disposes, so no stale
10
+ * reference to the previous generation's host survives a reload.
11
+ */
12
+ export function provideRssDb(context, db) {
13
+ return rssDbStore.provide(context, db);
14
+ }
4
15
  export function ensureRssMemoryDb() {
5
- if (!_db)
6
- _db = createInMemoryRssDb();
7
- return _db;
16
+ const provided = rssDbStore.tryUse() ?? _db;
17
+ if (provided)
18
+ return provided;
19
+ if (!_memoryDb)
20
+ _memoryDb = createInMemoryRssDb();
21
+ return _memoryDb;
8
22
  }
9
23
  export function getRssDb() {
10
24
  return ensureRssMemoryDb();
@@ -13,7 +27,9 @@ export function setRssDb(db) {
13
27
  _db = db;
14
28
  }
15
29
  export function resetRssDb() {
30
+ rssDbStore.clear();
16
31
  _db = null;
32
+ _memoryDb = null;
17
33
  }
18
34
  export function getRssSubs() {
19
35
  return ensureRssMemoryDb().models.get(RSS_SUBS_TABLE) ?? null;
@@ -1 +1 @@
1
- {"version":3,"file":"db-store.js","sourceRoot":"","sources":["../src/db-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,cAAc,GAGf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,cAAc,GAGf,MAAM,mBAAmB,CAAC;AAE3B,IAAI,GAAG,GAAuB,IAAI,CAAC;AAEnC,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC,GAAG;QAAE,GAAG,GAAG,mBAAmB,EAAE,CAAC;IACtC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,iBAAiB,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAsB;IAC7C,GAAG,GAAG,EAAE,CAAC;AACX,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,GAAG,GAAG,IAAI,CAAC;AACb,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,iBAAiB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,iBAAiB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"db-store.js","sourceRoot":"","sources":["../src/db-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,cAAc,GAGf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,qBAAqB,EAA6C,MAAM,yBAAyB,CAAC;AAC3G,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,cAAc,GAGf,MAAM,mBAAmB,CAAC;AAE3B,MAAM,UAAU,GAAG,qBAAqB,CAAc,QAAQ,CAAC,CAAC;AAEhE,IAAI,GAAG,GAAuB,IAAI,CAAC;AACnC,IAAI,SAAS,GAAuB,IAAI,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,OAA+B,EAAE,EAAe;IAC3E,OAAO,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC;IAC5C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,IAAI,CAAC,SAAS;QAAE,SAAS,GAAG,mBAAmB,EAAE,CAAC;IAClD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,iBAAiB,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAsB;IAC7C,GAAG,GAAG,EAAE,CAAC;AACX,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,GAAG,GAAG,IAAI,CAAC;IACX,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,iBAAiB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,iBAAiB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC;AAChE,CAAC"}
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { DEFAULT_RSS_CONFIG, fetchFeed, formatFeedPreview, resolveRssConfig, stripHtml, } from './feed.js';
2
2
  export type { FeedItem, RssConfig } from './feed.js';
3
- export { getRssDb, getRssSeen, getRssSubs, setRssDb, ensureRssMemoryDb, resetRssDb, } from './db-store.js';
3
+ export { getRssDb, getRssSeen, getRssSubs, provideRssDb, setRssDb, ensureRssMemoryDb, resetRssDb, } from './db-store.js';
4
4
  export { extractChannelInfo, SMOKE_CHANNEL } from './channel.js';
5
5
  export { checkSubscriptions, pollAllFeeds, formatNewItems, setRssOutboundPush } from './poll.js';
6
6
  export type { RssOutboundPush, CheckResult } from './poll.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACjG,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACjG,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { DEFAULT_RSS_CONFIG, fetchFeed, formatFeedPreview, resolveRssConfig, stripHtml, } from './feed.js';
2
- export { getRssDb, getRssSeen, getRssSubs, setRssDb, ensureRssMemoryDb, resetRssDb, } from './db-store.js';
2
+ export { getRssDb, getRssSeen, getRssSubs, provideRssDb, setRssDb, ensureRssMemoryDb, resetRssDb, } from './db-store.js';
3
3
  export { extractChannelInfo, SMOKE_CHANNEL } from './channel.js';
4
4
  export { checkSubscriptions, pollAllFeeds, formatNewItems, setRssOutboundPush } from './poll.js';
5
5
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC"}
package/lib/poll.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAa,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAGrE,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAIpB,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAErE;AAED,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,IAAI,CAE3D;AAMD,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY7F;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrF;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AA4BD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,SAAS,CAAC;CACnB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuCvB;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAelD;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAO1E"}
1
+ {"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAa,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAGrE,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAIpB,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAErE;AAED,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,IAAI,CAE3D;AAMD,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY7F;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrF;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AA4BD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,SAAS,CAAC;CACnB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuCvB;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBlD;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAO1E"}
package/lib/poll.js CHANGED
@@ -129,11 +129,13 @@ export async function cleanOldSeen() {
129
129
  const all = await Seen.select();
130
130
  const expired = all.filter((r) => typeof r.seen_at === 'string' && r.seen_at < cutoffStr);
131
131
  for (const row of expired) {
132
- await Seen.delete().where({ id: row.id });
132
+ // 表结构没有 id 列,按业务键 (feed_url, item_guid) 删除。
133
+ await Seen.delete().where({ feed_url: row.feed_url, item_guid: row.item_guid });
133
134
  }
134
135
  }
135
- catch {
136
- // Cleanup failure must not break the main flow.
136
+ catch (e) {
137
+ // Cleanup failure must not break the main flow, but it must be visible.
138
+ console.warn(`[rss] cleanOldSeen failed: ${e instanceof Error ? e.message : String(e)}`);
137
139
  }
138
140
  }
139
141
  /**
package/lib/poll.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"poll.js","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,SAAS,EAAiC,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAUvD,IAAI,aAAa,GAA2B,IAAI,CAAC;AAEjD,MAAM,UAAU,kBAAkB,CAAC,IAA4B;IAC7D,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,EAAE;IACT,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,KAAiB,EAAE,QAAgB;IACnF,MAAM,KAAK,GAAG,CAAC,GAAG,SAAS,MAAM,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,MAAM,GAAG,QAAQ,UAAU,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,KAAiB;IACpE,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACnF,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,CAAC,MAAM,CAAC;gBAChB,QAAQ,EAAE,OAAO;gBACjB,SAAS,EAAE,IAAI,CAAC,IAAI;gBACpB,UAAU,EAAE,IAAI,CAAC,KAAK;gBACtB,OAAO,EAAE,EAAE,EAAE;aACd,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAQD,KAAK,UAAU,iBAAiB,CAAC,OAAe,EAAE,OAAe;IAC/D,MAAM,IAAI,GAAG,aAAa,CAAC;IAC3B,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,CAAC;IAC7B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IAChE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS;YAAE,SAAS;QACzC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC;gBACT,WAAW;gBACX,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,IAAI,WAAW,CAAC;gBAClD,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,IAAI,SAAS,CAAC;gBAClD,SAAS;gBACT,OAAO;aACR,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,yDAAyD;QAC3D,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAGxC;IACC,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACnB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACtE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YAC9D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC1E,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAChF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC;gBACpC,SAAS;YACX,CAAC;YACD,MAAM,aAAa,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACnC,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC;YAC5B,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,IAAI,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC7E,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,IAAI,MAAM,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,YAAa,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC5E,MAAM,QAAQ,GAAG,aAAa;QAC5B,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;QAChD,CAAC,CAAC,0BAA0B,CAAC;IAC/B,MAAM,MAAM,GAAG,QAAQ,GAAG,CAAC;QACzB,CAAC,CAAC,UAAU,QAAQ,QAAQ,QAAQ,EAAE;QACtC,CAAC,CAAC,YAAY,CAAC;IACjB,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC1E,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QAC1B,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;QAC1F,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAiB;IAClD,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/E,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC9E,OAAO,kBAAkB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAC9C,CAAC"}
1
+ {"version":3,"file":"poll.js","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-rss",
3
- "version": "3.0.4",
3
+ "version": "3.0.6",
4
4
  "description": "RSS/Atom feed subscription plugin for Zhin.js (Plugin Runtime)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -14,7 +14,7 @@
14
14
  "./package.json": "./package.json"
15
15
  },
16
16
  "files": [
17
- "plugin.ts",
17
+ "plugin.js",
18
18
  "schema.json",
19
19
  "commands",
20
20
  "src",
@@ -41,18 +41,18 @@
41
41
  "license": "MIT",
42
42
  "dependencies": {
43
43
  "rss-parser": "^3.13.0",
44
- "@zhin.js/command": "1.0.2",
45
- "@zhin.js/plugin-runtime": "1.1.0"
44
+ "@zhin.js/command": "1.0.4",
45
+ "@zhin.js/plugin-runtime": "1.1.1"
46
46
  },
47
47
  "devDependencies": {
48
48
  "typescript": "^6.0.3",
49
49
  "vitest": "^4.1.10",
50
50
  "zod": "^4.4.3",
51
- "@zhin.js/agent": "1.0.5"
51
+ "@zhin.js/agent": "1.0.7"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "zod": "^4.0.0",
55
- "@zhin.js/agent": "1.0.5"
55
+ "@zhin.js/agent": "1.0.7"
56
56
  },
57
57
  "peerDependenciesMeta": {
58
58
  "@zhin.js/agent": {
@@ -77,7 +77,7 @@
77
77
  "zhin": {
78
78
  "protocol": 1,
79
79
  "type": "plugin",
80
- "entry": "./plugin.ts",
80
+ "entry": "./plugin.js",
81
81
  "engine": "^1.0.0",
82
82
  "runtime": "trusted",
83
83
  "features": [
package/plugin.js ADDED
@@ -0,0 +1,91 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { definePlugin, databaseHostToken, outboundHostToken, scheduleHostToken, } from '@zhin.js/plugin-runtime';
3
+ import { fetchFeed, resolveRssConfig } from "./lib/feed.js";
4
+ import { ensureRssMemoryDb, getRssSubs, provideRssDb, RSS_SEEN_TABLE, RSS_SUBS_TABLE, } from "./lib/db-store.js";
5
+ import { setRssAgentDeps } from "./lib/rss-agent-deps.js";
6
+ import { cleanOldSeen, pollAllFeeds, setRssOutboundPush } from "./lib/poll.js";
7
+ function defineRssTables(db) {
8
+ db.define(RSS_SUBS_TABLE, {
9
+ url: { type: 'text', nullable: false },
10
+ feed_title: { type: 'text', default: '' },
11
+ adapter_name: { type: 'text', nullable: false },
12
+ endpoint_id: { type: 'text', default: '' },
13
+ channel_type: { type: 'text', default: 'private' },
14
+ channel_id: { type: 'text', nullable: false },
15
+ creator_id: { type: 'text', default: '' },
16
+ creator_name: { type: 'text', default: '' },
17
+ created_at: { type: 'text', default: '' },
18
+ });
19
+ db.define(RSS_SEEN_TABLE, {
20
+ feed_url: { type: 'text', nullable: false },
21
+ item_guid: { type: 'text', nullable: false },
22
+ item_title: { type: 'text', default: '' },
23
+ seen_at: { type: 'text', default: '' },
24
+ });
25
+ }
26
+ /**
27
+ * Plugin Runtime:
28
+ * - Commands: add/list/remove/check.
29
+ * - DB: prefer `databaseHostToken`; else in-memory.
30
+ * - Outbound: `outboundHostToken` pushes new items to subscriber channels.
31
+ * - Cron: `scheduleHostToken` poll job when available.
32
+ */
33
+ export default definePlugin({
34
+ name: 'rss',
35
+ metadata: {
36
+ displayName: 'RSS',
37
+ },
38
+ setup(context) {
39
+ const config = resolveRssConfig(context.config.get());
40
+ if (context.resources.has(databaseHostToken)) {
41
+ const host = context.resources.use(databaseHostToken);
42
+ defineRssTables(host);
43
+ // provide 自动挂 lifecycle:代际结束反注册,避免悬挂到上一代的 host
44
+ provideRssDb(context, host);
45
+ }
46
+ else {
47
+ ensureRssMemoryDb();
48
+ }
49
+ if (context.resources.has(outboundHostToken)) {
50
+ const outbound = context.resources.use(outboundHostToken);
51
+ setRssOutboundPush(async (input) => {
52
+ await outbound.send({
53
+ adapter: input.adapterName,
54
+ endpointId: input.endpointId,
55
+ channelType: input.channelType,
56
+ channelId: input.channelId,
57
+ content: input.content,
58
+ });
59
+ });
60
+ context.lifecycle.add(() => setRssOutboundPush(null));
61
+ }
62
+ setRssAgentDeps({
63
+ getSubs: () => getRssSubs(),
64
+ fetchFeed: (url) => fetchFeed(url, config.timeout).then((f) => ({
65
+ title: f.title,
66
+ items: f.items.map((i) => ({ title: i.title, link: i.link })),
67
+ })),
68
+ });
69
+ if (!context.resources.has(scheduleHostToken))
70
+ return;
71
+ const schedule = context.resources.use(scheduleHostToken);
72
+ const dispose = schedule.register({
73
+ id: 'rss/poll_feeds',
74
+ cron: config.pollCron,
75
+ description: 'Poll RSS subscriptions',
76
+ async execute() {
77
+ await pollAllFeeds(config);
78
+ },
79
+ });
80
+ const disposeClean = schedule.register({
81
+ id: 'rss/clean_old_seen',
82
+ cron: '0 0 4 * * *',
83
+ description: 'Clean seen records older than 7 days',
84
+ async execute() {
85
+ await cleanOldSeen();
86
+ },
87
+ });
88
+ context.lifecycle.add(dispose);
89
+ context.lifecycle.add(disposeClean);
90
+ },
91
+ });
package/src/db-store.ts CHANGED
@@ -6,6 +6,7 @@ export {
6
6
  type RssModel,
7
7
  } from './memory-store.js';
8
8
 
9
+ import { createGenerationStore, type Dispose, type GenerationStoreContext } from '@zhin.js/plugin-runtime';
9
10
  import {
10
11
  createInMemoryRssDb,
11
12
  RSS_SEEN_TABLE,
@@ -14,11 +15,25 @@ import {
14
15
  type RssModel,
15
16
  } from './memory-store.js';
16
17
 
18
+ const rssDbStore = createGenerationStore<RssMemoryDb>('rss/db');
19
+
17
20
  let _db: RssMemoryDb | null = null;
21
+ let _memoryDb: RssMemoryDb | null = null;
22
+
23
+ /**
24
+ * Generation-owned database binding used by Plugin Runtime setup().
25
+ * Auto-unregisters when the generation lifecycle disposes, so no stale
26
+ * reference to the previous generation's host survives a reload.
27
+ */
28
+ export function provideRssDb(context: GenerationStoreContext, db: RssMemoryDb): Dispose {
29
+ return rssDbStore.provide(context, db);
30
+ }
18
31
 
19
32
  export function ensureRssMemoryDb(): RssMemoryDb {
20
- if (!_db) _db = createInMemoryRssDb();
21
- return _db;
33
+ const provided = rssDbStore.tryUse() ?? _db;
34
+ if (provided) return provided;
35
+ if (!_memoryDb) _memoryDb = createInMemoryRssDb();
36
+ return _memoryDb;
22
37
  }
23
38
 
24
39
  export function getRssDb(): RssMemoryDb | null {
@@ -30,7 +45,9 @@ export function setRssDb(db: RssMemoryDb | null): void {
30
45
  }
31
46
 
32
47
  export function resetRssDb(): void {
48
+ rssDbStore.clear();
33
49
  _db = null;
50
+ _memoryDb = null;
34
51
  }
35
52
 
36
53
  export function getRssSubs(): RssModel | null {
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@ export {
10
10
  getRssDb,
11
11
  getRssSeen,
12
12
  getRssSubs,
13
+ provideRssDb,
13
14
  setRssDb,
14
15
  ensureRssMemoryDb,
15
16
  resetRssDb,
package/src/poll.ts CHANGED
@@ -149,10 +149,12 @@ export async function cleanOldSeen(): Promise<void> {
149
149
  const all = await Seen.select();
150
150
  const expired = all.filter((r) => typeof r.seen_at === 'string' && r.seen_at < cutoffStr);
151
151
  for (const row of expired) {
152
- await Seen.delete().where({ id: row.id });
152
+ // 表结构没有 id 列,按业务键 (feed_url, item_guid) 删除。
153
+ await Seen.delete().where({ feed_url: row.feed_url, item_guid: row.item_guid });
153
154
  }
154
- } catch {
155
- // Cleanup failure must not break the main flow.
155
+ } catch (e) {
156
+ // Cleanup failure must not break the main flow, but it must be visible.
157
+ console.warn(`[rss] cleanOldSeen failed: ${e instanceof Error ? e.message : String(e)}`);
156
158
  }
157
159
  }
158
160
 
package/plugin.ts DELETED
@@ -1,103 +0,0 @@
1
- import {
2
- definePlugin,
3
- databaseHostToken,
4
- outboundHostToken,
5
- scheduleHostToken,
6
- } from '@zhin.js/plugin-runtime';
7
- import { fetchFeed, resolveRssConfig, type RssConfig } from './src/feed.js';
8
- import {
9
- ensureRssMemoryDb,
10
- getRssSubs,
11
- setRssDb,
12
- RSS_SEEN_TABLE,
13
- RSS_SUBS_TABLE,
14
- } from './src/db-store.js';
15
- import { setRssAgentDeps } from './src/rss-agent-deps.js';
16
- import { cleanOldSeen, pollAllFeeds, setRssOutboundPush } from './src/poll.js';
17
-
18
- function defineRssTables(db: { define: (name: string, schema: Record<string, unknown>) => void }): void {
19
- db.define(RSS_SUBS_TABLE, {
20
- url: { type: 'text', nullable: false },
21
- feed_title: { type: 'text', default: '' },
22
- adapter_name: { type: 'text', nullable: false },
23
- endpoint_id: { type: 'text', default: '' },
24
- channel_type: { type: 'text', default: 'private' },
25
- channel_id: { type: 'text', nullable: false },
26
- creator_id: { type: 'text', default: '' },
27
- creator_name: { type: 'text', default: '' },
28
- created_at: { type: 'text', default: '' },
29
- });
30
- db.define(RSS_SEEN_TABLE, {
31
- feed_url: { type: 'text', nullable: false },
32
- item_guid: { type: 'text', nullable: false },
33
- item_title: { type: 'text', default: '' },
34
- seen_at: { type: 'text', default: '' },
35
- });
36
- }
37
-
38
- /**
39
- * Plugin Runtime:
40
- * - Commands: add/list/remove/check.
41
- * - DB: prefer `databaseHostToken`; else in-memory.
42
- * - Outbound: `outboundHostToken` pushes new items to subscriber channels.
43
- * - Cron: `scheduleHostToken` poll job when available.
44
- */
45
- export default definePlugin<RssConfig>({
46
- name: 'rss',
47
- metadata: {
48
- displayName: 'RSS',
49
- },
50
- setup(context) {
51
- const config = resolveRssConfig(context.config.get());
52
- if (context.resources.has(databaseHostToken)) {
53
- const host = context.resources.use(databaseHostToken);
54
- defineRssTables(host);
55
- setRssDb(host);
56
- } else {
57
- ensureRssMemoryDb();
58
- }
59
-
60
- if (context.resources.has(outboundHostToken)) {
61
- const outbound = context.resources.use(outboundHostToken);
62
- setRssOutboundPush(async (input) => {
63
- await outbound.send({
64
- adapter: input.adapterName,
65
- endpointId: input.endpointId,
66
- channelType: input.channelType,
67
- channelId: input.channelId,
68
- content: input.content,
69
- });
70
- });
71
- context.lifecycle.add(() => setRssOutboundPush(null));
72
- }
73
-
74
- setRssAgentDeps({
75
- getSubs: () => getRssSubs() as { select: () => Promise<unknown[]> } | null,
76
- fetchFeed: (url) => fetchFeed(url, config.timeout).then((f) => ({
77
- title: f.title,
78
- items: f.items.map((i) => ({ title: i.title, link: i.link })),
79
- })),
80
- });
81
-
82
- if (!context.resources.has(scheduleHostToken)) return;
83
- const schedule = context.resources.use(scheduleHostToken);
84
- const dispose = schedule.register({
85
- id: 'rss/poll_feeds',
86
- cron: config.pollCron,
87
- description: 'Poll RSS subscriptions',
88
- async execute() {
89
- await pollAllFeeds(config);
90
- },
91
- });
92
- const disposeClean = schedule.register({
93
- id: 'rss/clean_old_seen',
94
- cron: '0 0 4 * * *',
95
- description: 'Clean seen records older than 7 days',
96
- async execute() {
97
- await cleanOldSeen();
98
- },
99
- });
100
- context.lifecycle.add(dispose);
101
- context.lifecycle.add(disposeClean);
102
- },
103
- });