@zhin.js/plugin-rss 1.1.12 → 1.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/rss-add/[url]/index.js +37 -35
- package/commands/rss-add/[url]/index.ts +40 -38
- package/commands/rss-remove/[url]/index.js +20 -14
- package/commands/rss-remove/[url]/index.ts +19 -13
- package/lib/channel.d.ts +2 -0
- package/lib/channel.d.ts.map +1 -1
- package/lib/channel.js +10 -6
- package/lib/channel.js.map +1 -1
- package/lib/poll.d.ts.map +1 -1
- package/lib/poll.js +9 -4
- package/lib/poll.js.map +1 -1
- package/lib/runtime.d.ts +4 -0
- package/lib/runtime.d.ts.map +1 -1
- package/lib/runtime.js.map +1 -1
- package/lib/target-migration.d.ts +14 -0
- package/lib/target-migration.d.ts.map +1 -0
- package/lib/target-migration.js +94 -0
- package/lib/target-migration.js.map +1 -0
- package/package.json +7 -7
- package/plugin.js +17 -12
- package/src/channel.ts +11 -7
- package/src/poll.ts +14 -4
- package/src/runtime.ts +4 -0
- package/src/target-migration.ts +116 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { subscriptionMigrationScope } from "../../../lib/target-migration.js";
|
|
2
3
|
import { rssMessages as t } from "../../../lib/i18n.js";
|
|
3
4
|
import { defineCommand } from 'zhin.js/command';
|
|
4
5
|
import { channelSourceError, extractChannelInfo, subscriptionScope } from "../../../lib/channel.js";
|
|
@@ -22,40 +23,41 @@ export default defineCommand({
|
|
|
22
23
|
const channel = extractChannelInfo(input);
|
|
23
24
|
if (!channel)
|
|
24
25
|
return channelSourceError(input, locale);
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
locale,
|
|
58
|
-
}
|
|
59
|
-
return
|
|
26
|
+
const run = async () => {
|
|
27
|
+
const cfg = resolveRssConfig(config);
|
|
28
|
+
const existing = await Subs.select().where({
|
|
29
|
+
url,
|
|
30
|
+
...subscriptionScope(channel),
|
|
31
|
+
});
|
|
32
|
+
if (existing.length > 0)
|
|
33
|
+
return t(locale, 'existing');
|
|
34
|
+
const currentSubs = await Subs.select().where({
|
|
35
|
+
...subscriptionScope(channel),
|
|
36
|
+
});
|
|
37
|
+
if (currentSubs.length >= cfg.maxPerGroup) {
|
|
38
|
+
return t(locale, 'limit', { max: cfg.maxPerGroup });
|
|
39
|
+
}
|
|
40
|
+
let feedTitle = '';
|
|
41
|
+
try {
|
|
42
|
+
const { title, items } = await fetchFeed(url, cfg.timeout);
|
|
43
|
+
feedTitle = title;
|
|
44
|
+
await markItemsSeen(runtime, url, items);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
return t(locale, 'loadFailed', { error: e.message });
|
|
48
|
+
}
|
|
49
|
+
await Subs.insert({
|
|
50
|
+
url,
|
|
51
|
+
feed_title: feedTitle,
|
|
52
|
+
...subscriptionScope(channel),
|
|
53
|
+
creator_id: channel.senderId,
|
|
54
|
+
creator_name: channel.senderName,
|
|
55
|
+
created_at: new Date().toISOString(),
|
|
56
|
+
locale,
|
|
57
|
+
});
|
|
58
|
+
return t(locale, 'added', { feed: feedTitle || url });
|
|
59
|
+
};
|
|
60
|
+
return runtime.migrationScopes ? runtime.migrationScopes.run({ scope: subscriptionMigrationScope({ target: channel.target,
|
|
61
|
+
adapterName: channel.adapterName, endpointKey: channel.endpointKey, channelType: channel.channelType, channelId: channel.channelId }), run }) : run();
|
|
60
62
|
},
|
|
61
63
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { subscriptionMigrationScope } from '../../../src/target-migration.js';
|
|
1
2
|
import { rssMessages as t } from '../../../src/i18n.js';
|
|
2
3
|
import { defineCommand } from 'zhin.js/command';
|
|
3
4
|
import { channelSourceError, extractChannelInfo, subscriptionScope } from '../../../src/channel.js';
|
|
@@ -20,43 +21,44 @@ export default defineCommand<RssConfig>({
|
|
|
20
21
|
|
|
21
22
|
const channel = extractChannelInfo(input);
|
|
22
23
|
if (!channel) return channelSourceError(input, locale);
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return
|
|
24
|
+
const run = async () => {
|
|
25
|
+
const cfg = resolveRssConfig(config);
|
|
26
|
+
|
|
27
|
+
const existing = await Subs.select().where({
|
|
28
|
+
url,
|
|
29
|
+
...subscriptionScope(channel),
|
|
30
|
+
});
|
|
31
|
+
if (existing.length > 0) return t(locale, 'existing');
|
|
32
|
+
|
|
33
|
+
const currentSubs = await Subs.select().where({
|
|
34
|
+
...subscriptionScope(channel),
|
|
35
|
+
});
|
|
36
|
+
if (currentSubs.length >= cfg.maxPerGroup) {
|
|
37
|
+
return t(locale, 'limit', { max: cfg.maxPerGroup });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let feedTitle = '';
|
|
41
|
+
try {
|
|
42
|
+
const { title, items } = await fetchFeed(url, cfg.timeout);
|
|
43
|
+
feedTitle = title;
|
|
44
|
+
await markItemsSeen(runtime, url, items);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
return t(locale, 'loadFailed', { error: (e as Error).message });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await Subs.insert({
|
|
50
|
+
url,
|
|
51
|
+
feed_title: feedTitle,
|
|
52
|
+
...subscriptionScope(channel),
|
|
53
|
+
creator_id: channel.senderId,
|
|
54
|
+
creator_name: channel.senderName,
|
|
55
|
+
created_at: new Date().toISOString(),
|
|
56
|
+
locale,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return t(locale, 'added', { feed: feedTitle || url });
|
|
60
|
+
};
|
|
61
|
+
return runtime.migrationScopes ? runtime.migrationScopes.run({ scope: subscriptionMigrationScope({ target: channel.target,
|
|
62
|
+
adapterName: channel.adapterName, endpointKey: channel.endpointKey, channelType: channel.channelType, channelId: channel.channelId }), run }) : run();
|
|
61
63
|
},
|
|
62
64
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { subscriptionMigrationScope } from "../../../lib/target-migration.js";
|
|
2
3
|
import { rssMessages as t } from "../../../lib/i18n.js";
|
|
3
4
|
import { defineCommand } from 'zhin.js/command';
|
|
4
5
|
import { channelSourceError, extractChannelInfo, subscriptionScope } from "../../../lib/channel.js";
|
|
@@ -8,7 +9,8 @@ export default defineCommand({
|
|
|
8
9
|
description: '取消一个 RSS 订阅', descriptionI18n: { en: "Unsubscribe from an RSS feed" },
|
|
9
10
|
params: { url: { type: 'string' } },
|
|
10
11
|
async execute({ params, input, use, locale }) {
|
|
11
|
-
const
|
|
12
|
+
const runtime = use(rssRuntimeToken);
|
|
13
|
+
const Subs = getRssSubs(runtime.db);
|
|
12
14
|
if (!Subs)
|
|
13
15
|
return t(locale, 'databaseUnavailable');
|
|
14
16
|
const url = String(params.url ?? '').trim();
|
|
@@ -17,18 +19,22 @@ export default defineCommand({
|
|
|
17
19
|
const channel = extractChannelInfo(input);
|
|
18
20
|
if (!channel)
|
|
19
21
|
return channelSourceError(input, locale);
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
const run = async () => {
|
|
23
|
+
const rows = await Subs.select().where({
|
|
24
|
+
url,
|
|
25
|
+
...subscriptionScope(channel),
|
|
26
|
+
});
|
|
27
|
+
if (rows.length === 0)
|
|
28
|
+
return t(locale, 'notFound');
|
|
29
|
+
const row = rows[0];
|
|
30
|
+
// 表结构没有 id 列,删除必须按业务键匹配(与上面的 select 条件一致)。
|
|
31
|
+
await Subs.delete().where({
|
|
32
|
+
url,
|
|
33
|
+
...subscriptionScope(channel),
|
|
34
|
+
});
|
|
35
|
+
return t(locale, 'removed', { feed: String(row.feed_title || url) });
|
|
36
|
+
};
|
|
37
|
+
return runtime.migrationScopes ? runtime.migrationScopes.run({ scope: subscriptionMigrationScope({ target: channel.target,
|
|
38
|
+
adapterName: channel.adapterName, endpointKey: channel.endpointKey, channelType: channel.channelType, channelId: channel.channelId }), run }) : run();
|
|
33
39
|
},
|
|
34
40
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { subscriptionMigrationScope } from '../../../src/target-migration.js';
|
|
1
2
|
import { rssMessages as t } from '../../../src/i18n.js';
|
|
2
3
|
import { defineCommand } from 'zhin.js/command';
|
|
3
4
|
import { channelSourceError, extractChannelInfo, subscriptionScope } from '../../../src/channel.js';
|
|
@@ -9,7 +10,8 @@ export default defineCommand<RssConfig>({
|
|
|
9
10
|
description: '取消一个 RSS 订阅', descriptionI18n: { en: "Unsubscribe from an RSS feed" },
|
|
10
11
|
params: { url: { type: 'string' } },
|
|
11
12
|
async execute({ params, input, use, locale }) {
|
|
12
|
-
const
|
|
13
|
+
const runtime = use(rssRuntimeToken);
|
|
14
|
+
const Subs = getRssSubs(runtime.db);
|
|
13
15
|
if (!Subs) return t(locale, 'databaseUnavailable');
|
|
14
16
|
|
|
15
17
|
const url = String(params.url ?? '').trim();
|
|
@@ -17,19 +19,23 @@ export default defineCommand<RssConfig>({
|
|
|
17
19
|
|
|
18
20
|
const channel = extractChannelInfo(input);
|
|
19
21
|
if (!channel) return channelSourceError(input, locale);
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const run = async () => {
|
|
23
|
+
const rows = await Subs.select().where({
|
|
24
|
+
url,
|
|
25
|
+
...subscriptionScope(channel),
|
|
26
|
+
});
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
if (rows.length === 0) return t(locale, 'notFound');
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
const row = rows[0]!;
|
|
31
|
+
// 表结构没有 id 列,删除必须按业务键匹配(与上面的 select 条件一致)。
|
|
32
|
+
await Subs.delete().where({
|
|
33
|
+
url,
|
|
34
|
+
...subscriptionScope(channel),
|
|
35
|
+
});
|
|
36
|
+
return t(locale, 'removed', { feed: String(row.feed_title || url) });
|
|
37
|
+
};
|
|
38
|
+
return runtime.migrationScopes ? runtime.migrationScopes.run({ scope: subscriptionMigrationScope({ target: channel.target,
|
|
39
|
+
adapterName: channel.adapterName, endpointKey: channel.endpointKey, channelType: channel.channelType, channelId: channel.channelId }), run }) : run();
|
|
34
40
|
},
|
|
35
41
|
});
|
package/lib/channel.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { type DeliveryTarget } from 'zhin.js/plugin-runtime';
|
|
1
2
|
import type { Locale } from 'zhin.js/i18n';
|
|
2
3
|
/** A subscription destination uses public Message fields, never CapabilityId internals. */
|
|
3
4
|
export interface ChannelInfo {
|
|
5
|
+
readonly target: DeliveryTarget;
|
|
4
6
|
adapterName: string;
|
|
5
7
|
endpointKey: string;
|
|
6
8
|
channelType: 'private' | 'group' | 'channel';
|
package/lib/channel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,2FAA2F;AAE3F,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,wBAAwB,2MAAsC,CAAC;AAC5E,eAAO,MAAM,2BAA2B,iNAAuC,CAAC;AAehF,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,GAAE,MAAgB,GAAG,MAAM,CAEnF;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,cAAc,EAA2C,MAAM,wBAAwB,CAAC;AAC5H,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,2FAA2F;AAE3F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,wBAAwB,2MAAsC,CAAC;AAC5E,eAAO,MAAM,2BAA2B,iNAAuC,CAAC;AAehF,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,GAAE,MAAgB,GAAG,MAAM,CAEnF;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAqBrE;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ9E"}
|
package/lib/channel.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createDeliveryTarget, encodeTaskTarget, encodeStorageIdentity } from 'zhin.js/plugin-runtime';
|
|
1
2
|
import { rssMessages as t } from './i18n.js';
|
|
2
3
|
export const CHANNEL_REQUIRED_MESSAGE = '请在机器人私聊、群聊或频道内执行此命令;当前调用没有有效的订阅会话';
|
|
3
4
|
export const UNSUPPORTED_ADDRESS_MESSAGE = '暂不支持线程/父频道寻址的订阅,请在无需线程或父频道信息的会话内执行';
|
|
@@ -25,15 +26,17 @@ export function extractChannelInfo(input) {
|
|
|
25
26
|
const kind = conversation.kind;
|
|
26
27
|
if (kind !== 'private' && kind !== 'group' && kind !== 'channel')
|
|
27
28
|
return null;
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const endpoint = isRecord(conversation.endpoint) ? conversation.endpoint : {};
|
|
30
|
+
if (!isIdentifier(endpoint.adapter) || !isIdentifier(endpoint.id) || !isIdentifier(conversation.id))
|
|
30
31
|
return null;
|
|
32
|
+
const target = createDeliveryTarget({ conversation: conversation });
|
|
31
33
|
const sender = input.sender;
|
|
32
34
|
if (sender !== undefined && (!isRecord(sender) || !isIdentifier(sender.id)))
|
|
33
35
|
return null;
|
|
34
36
|
return {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
target,
|
|
38
|
+
adapterName: target.endpoint.adapter,
|
|
39
|
+
endpointKey: target.endpoint.id,
|
|
37
40
|
channelType: kind,
|
|
38
41
|
channelId: conversation.id,
|
|
39
42
|
senderId: isRecord(sender) && isIdentifier(sender.id) ? sender.id : '',
|
|
@@ -43,8 +46,9 @@ export function extractChannelInfo(input) {
|
|
|
43
46
|
/** Complete subscription scope, including the bot instance for multi-endpoint adapters. */
|
|
44
47
|
export function subscriptionScope(channel) {
|
|
45
48
|
return {
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
target_json: JSON.stringify(encodeTaskTarget(channel.target)),
|
|
50
|
+
adapter_name: encodeStorageIdentity(channel.adapterName),
|
|
51
|
+
endpoint_id: encodeStorageIdentity(channel.endpointKey),
|
|
48
52
|
channel_type: channel.channelType,
|
|
49
53
|
channel_id: channel.channelId,
|
|
50
54
|
};
|
package/lib/channel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
|
package/lib/poll.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE1D;;GAEG;AACH,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAAgB,GAAG,MAAM,CAYvH;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAc1G;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;AA2CD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE;IACrE,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,WAAW,CAAC,CAwCvB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBrE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAQ5E"}
|
package/lib/poll.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeTaskTarget } from 'zhin.js/plugin-runtime';
|
|
1
2
|
import { resolveLocale } from 'zhin.js/i18n';
|
|
2
3
|
import { rssMessages as t } from './i18n.js';
|
|
3
4
|
/**
|
|
@@ -39,7 +40,8 @@ export async function markItemsSeen(runtime, feedUrl, items) {
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
|
-
async function pushToSubscribers(
|
|
43
|
+
async function pushToSubscribers(input) {
|
|
44
|
+
const { runtime, feed: { url: feedUrl, title: feedTitle, items } } = input;
|
|
43
45
|
const push = runtime.outbound;
|
|
44
46
|
const Subs = getRssSubs(runtime.db);
|
|
45
47
|
if (!push || !Subs)
|
|
@@ -57,7 +59,10 @@ async function pushToSubscribers(runtime, feedUrl, feedTitle, items) {
|
|
|
57
59
|
|| (channelType !== 'private' && channelType !== 'group' && channelType !== 'channel'))
|
|
58
60
|
continue;
|
|
59
61
|
try {
|
|
62
|
+
const target = sub.target_json == null ? undefined
|
|
63
|
+
: decodeTaskTarget(JSON.parse(String(sub.target_json)));
|
|
60
64
|
await push({
|
|
65
|
+
...(target ? { target } : {}),
|
|
61
66
|
adapterName,
|
|
62
67
|
endpointKey,
|
|
63
68
|
channelType,
|
|
@@ -67,8 +72,8 @@ async function pushToSubscribers(runtime, feedUrl, feedTitle, items) {
|
|
|
67
72
|
});
|
|
68
73
|
pushed += 1;
|
|
69
74
|
}
|
|
70
|
-
catch {
|
|
71
|
-
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.warn('[rss] subscription delivery failed:', error instanceof Error ? error.message : String(error));
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
return pushed;
|
|
@@ -101,7 +106,7 @@ export async function checkSubscriptions(runtime, options) {
|
|
|
101
106
|
totalNew += newItems.length;
|
|
102
107
|
const body = formatNewItems(title || url, newItems, runtime.config.maxItems, locale);
|
|
103
108
|
parts.push(body);
|
|
104
|
-
pushed += await pushToSubscribers(runtime, url, title || url, newItems);
|
|
109
|
+
pushed += await pushToSubscribers({ runtime, feed: { url, title: title || url, items: newItems } });
|
|
105
110
|
}
|
|
106
111
|
catch (e) {
|
|
107
112
|
parts.push(t(locale, 'checkFailed', { url, error: e.message }));
|
package/lib/poll.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poll.js","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAe,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,WAAW,IAAI,CAAC,EAAE,MAAM,WAAW,CAAC;AAC7C;;GAEG;AACH,OAAO,EAAE,SAAS,EAAiB,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGvD,SAAS,EAAE;IACT,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,KAAiB,EAAE,QAAgB,EAAE,SAAiB,OAAO;IAC7G,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACjF,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,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAmB,EAAE,OAAe,EAAE,KAAiB;IACzF,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpC,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;
|
|
1
|
+
{"version":3,"file":"poll.js","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"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"}
|
package/lib/runtime.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import type { DeliveryTarget, TargetMigrationScopes } from 'zhin.js/plugin-runtime';
|
|
1
2
|
import type { Locale } from 'zhin.js/i18n';
|
|
2
3
|
import type { RssConfig } from './feed.js';
|
|
3
4
|
import type { RssMemoryDb } from './memory-store.js';
|
|
4
5
|
import type { ChannelInfo } from './channel.js';
|
|
5
6
|
export type RssOutboundPush = (input: {
|
|
7
|
+
/** Explicit canonical target on new records; absent only at the pending historical-data boundary. */
|
|
8
|
+
readonly target?: DeliveryTarget;
|
|
6
9
|
readonly adapterName: string;
|
|
7
10
|
readonly endpointKey: string;
|
|
8
11
|
readonly channelType: ChannelInfo['channelType'];
|
|
@@ -11,6 +14,7 @@ export type RssOutboundPush = (input: {
|
|
|
11
14
|
readonly locale?: Locale;
|
|
12
15
|
}) => Promise<void>;
|
|
13
16
|
export interface RssRuntime {
|
|
17
|
+
readonly migrationScopes?: TargetMigrationScopes;
|
|
14
18
|
readonly locale?: Locale;
|
|
15
19
|
readonly db: RssMemoryDb;
|
|
16
20
|
readonly config: Readonly<RssConfig>;
|
package/lib/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEpB,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CAC3C;AAED,eAAO,MAAM,eAAe,qCAG3B,CAAC"}
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE;IACpC,qGAAqG;IACrG,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEpB,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CAC3C;AAED,eAAO,MAAM,eAAe,qCAG3B,CAAC"}
|
package/lib/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAwBtC,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CACxC,kBAAkB,EAClB,0BAA0B,CAC3B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type DeliveryTarget, type PluginDatabaseHost, type PluginDataMigrationProvider, type TargetMigrationScopes } from 'zhin.js/plugin-runtime';
|
|
2
|
+
/** Chat subscriptions use exact targets; historical selectors are inventory facts only. */
|
|
3
|
+
export declare function subscriptionMigrationScope(input: Readonly<{
|
|
4
|
+
target?: DeliveryTarget;
|
|
5
|
+
adapterName: string;
|
|
6
|
+
endpointKey: string;
|
|
7
|
+
channelType: string;
|
|
8
|
+
channelId: string;
|
|
9
|
+
}>): string;
|
|
10
|
+
export declare function createSubscriptionTargetMigration(input: Readonly<{
|
|
11
|
+
database: PluginDatabaseHost;
|
|
12
|
+
scopes: TargetMigrationScopes;
|
|
13
|
+
}>): PluginDataMigrationProvider;
|
|
14
|
+
//# sourceMappingURL=target-migration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-migration.d.ts","sourceRoot":"","sources":["../src/target-migration.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,2FAA2F;AAC3F,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,QAAQ,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,GACD,MAAM,CASR;AAED,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,QAAQ,CAAC;IAAE,QAAQ,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAA;CAAE,CAAC,GAC/E,2BAA2B,CA+E7B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { conversationRefKey } from 'zhin.js';
|
|
2
|
+
import { createRelationalTargetMigration, decodeTaskTarget, encodeStorageIdentity, encodeTaskTarget, orderedMigrationRows, targetMigrationDigest, } from 'zhin.js/plugin-runtime';
|
|
3
|
+
/** Chat subscriptions use exact targets; historical selectors are inventory facts only. */
|
|
4
|
+
export function subscriptionMigrationScope(input) {
|
|
5
|
+
return input.target
|
|
6
|
+
? `canonical:${conversationRefKey(input.target)}`
|
|
7
|
+
: `historical:${targetMigrationDigest({
|
|
8
|
+
adapter_name: input.adapterName,
|
|
9
|
+
endpoint_id: input.endpointKey,
|
|
10
|
+
channel_type: input.channelType,
|
|
11
|
+
channel_id: input.channelId,
|
|
12
|
+
})}`;
|
|
13
|
+
}
|
|
14
|
+
export function createSubscriptionTargetMigration(input) {
|
|
15
|
+
const table = 'rss_subscriptions';
|
|
16
|
+
return createRelationalTargetMigration({
|
|
17
|
+
...input,
|
|
18
|
+
domain: 'rss',
|
|
19
|
+
title: 'RSS subscription destinations',
|
|
20
|
+
sourceVersion: 'subscription-alias-v0',
|
|
21
|
+
tables: [table],
|
|
22
|
+
async readUnits(reader) {
|
|
23
|
+
const rows = await reader.model(table).select();
|
|
24
|
+
const grouped = new Map();
|
|
25
|
+
for (const row of rows) {
|
|
26
|
+
const query = {
|
|
27
|
+
adapter_name: row.adapter_name,
|
|
28
|
+
endpoint_id: row.endpoint_id,
|
|
29
|
+
channel_type: row.channel_type,
|
|
30
|
+
channel_id: row.channel_id,
|
|
31
|
+
target_json: row.target_json ?? null,
|
|
32
|
+
};
|
|
33
|
+
const id = targetMigrationDigest(query);
|
|
34
|
+
const unit = grouped.get(id) ?? {
|
|
35
|
+
query,
|
|
36
|
+
rows: [],
|
|
37
|
+
};
|
|
38
|
+
unit.rows.push(row);
|
|
39
|
+
grouped.set(id, unit);
|
|
40
|
+
}
|
|
41
|
+
return [...grouped.entries()]
|
|
42
|
+
.map(([id, unit]) => {
|
|
43
|
+
let target, status = 'unresolved';
|
|
44
|
+
if (unit.query.target_json !== null) {
|
|
45
|
+
try {
|
|
46
|
+
target = decodeTaskTarget(JSON.parse(String(unit.query.target_json)));
|
|
47
|
+
status = 'canonical';
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
status = 'corrupt';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const selectors = {
|
|
54
|
+
adapterName: String(unit.query.adapter_name),
|
|
55
|
+
endpointKey: String(unit.query.endpoint_id),
|
|
56
|
+
channelType: String(unit.query.channel_type),
|
|
57
|
+
channelId: String(unit.query.channel_id),
|
|
58
|
+
};
|
|
59
|
+
return {
|
|
60
|
+
id,
|
|
61
|
+
title: `RSS: ${selectors.channelType}/${selectors.channelId}`,
|
|
62
|
+
status,
|
|
63
|
+
scope: subscriptionMigrationScope({ ...selectors, ...(target ? { target } : {}) }),
|
|
64
|
+
records: [{ table, query: unit.query, rows: orderedMigrationRows(unit.rows) }],
|
|
65
|
+
summary: { ...selectors, duplicateRows: unit.rows.length },
|
|
66
|
+
};
|
|
67
|
+
})
|
|
68
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
69
|
+
},
|
|
70
|
+
rewrite(unit, target) {
|
|
71
|
+
const before = unit.records[0];
|
|
72
|
+
const patch = {
|
|
73
|
+
target_json: JSON.stringify(encodeTaskTarget(target)),
|
|
74
|
+
adapter_name: encodeStorageIdentity(target.endpoint.adapter),
|
|
75
|
+
endpoint_id: encodeStorageIdentity(target.endpoint.id),
|
|
76
|
+
channel_type: target.kind,
|
|
77
|
+
channel_id: target.id,
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
destinationScope: subscriptionMigrationScope({
|
|
81
|
+
target,
|
|
82
|
+
adapterName: target.endpoint.adapter,
|
|
83
|
+
endpointKey: target.endpoint.id,
|
|
84
|
+
channelType: target.kind,
|
|
85
|
+
channelId: target.id,
|
|
86
|
+
}),
|
|
87
|
+
writes: [
|
|
88
|
+
{ before, after: { table, query: patch, rows: before.rows.map((row) => ({ ...row, ...patch })) }, patch },
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=target-migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-migration.js","sourceRoot":"","sources":["../src/target-migration.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": "1.1.
|
|
3
|
+
"version": "1.1.14",
|
|
4
4
|
"description": "RSS/Atom feed subscription plugin for Zhin.js (Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -41,20 +41,20 @@
|
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"rss-parser": "^3.13.0",
|
|
44
|
-
"@zhin.js/
|
|
45
|
-
"@zhin.js/
|
|
46
|
-
"@zhin.js/
|
|
44
|
+
"@zhin.js/tool": "1.1.14",
|
|
45
|
+
"@zhin.js/skill": "1.1.12",
|
|
46
|
+
"@zhin.js/im-contract": "1.1.10"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"typescript": "^6.0.3",
|
|
50
50
|
"vitest": "^4.1.10",
|
|
51
51
|
"zod": "^4.4.3",
|
|
52
|
-
"zhin.js": "1.1.
|
|
52
|
+
"zhin.js": "1.1.20"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"zod": "^4.0.0",
|
|
56
|
-
"@zhin.js/command": "^1.1.
|
|
57
|
-
"zhin.js": "^1.1.
|
|
56
|
+
"@zhin.js/command": "^1.1.13",
|
|
57
|
+
"zhin.js": "^1.1.20"
|
|
58
58
|
},
|
|
59
59
|
"peerDependenciesMeta": {
|
|
60
60
|
"@zhin.js/command": {
|
package/plugin.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { DataMigrationError, pluginDataMigrationProviderToken, TargetMigrationScopes, pluginTaskProviderToken } from 'zhin.js/plugin-runtime';
|
|
3
|
+
import { createSubscriptionTargetMigration, subscriptionMigrationScope } from "./lib/target-migration.js";
|
|
2
4
|
import { projectLocaleToken, resolveLocale } from 'zhin.js/i18n';
|
|
3
5
|
import { definePlugin, logger, databaseHostToken, outboundHostToken, scheduleHostToken, } from 'zhin.js';
|
|
4
|
-
import { pluginTaskProviderToken } from 'zhin.js/plugin-runtime';
|
|
5
6
|
import { createAdministratorRssState } from "./lib/storage.js";
|
|
6
7
|
import { AdministratorRssTasks } from "./lib/admin-tasks.js";
|
|
7
8
|
import { resolveRssConfig } from "./lib/feed.js";
|
|
@@ -11,6 +12,7 @@ import { rssRuntimeToken } from "./lib/runtime.js";
|
|
|
11
12
|
function defineRssTables(db) {
|
|
12
13
|
db.define(RSS_SUBS_TABLE, {
|
|
13
14
|
url: { type: 'text', nullable: false },
|
|
15
|
+
target_json: { type: 'text', nullable: true },
|
|
14
16
|
feed_title: { type: 'text', default: '' },
|
|
15
17
|
adapter_name: { type: 'text', nullable: false },
|
|
16
18
|
endpoint_id: { type: 'text', default: '' },
|
|
@@ -20,7 +22,7 @@ function defineRssTables(db) {
|
|
|
20
22
|
creator_name: { type: 'text', default: '' },
|
|
21
23
|
created_at: { type: 'text', default: '' },
|
|
22
24
|
locale: { type: 'text', length: 16, default: 'zh-CN' },
|
|
23
|
-
}, { addColumns: ['locale'] });
|
|
25
|
+
}, { addColumns: ['locale', 'target_json'] });
|
|
24
26
|
db.define(RSS_SEEN_TABLE, {
|
|
25
27
|
feed_url: { type: 'text', nullable: false },
|
|
26
28
|
item_guid: { type: 'text', nullable: false },
|
|
@@ -48,24 +50,27 @@ export default definePlugin({
|
|
|
48
50
|
defineRssTables(host);
|
|
49
51
|
return host;
|
|
50
52
|
})() : createInMemoryRssDb();
|
|
53
|
+
const migrationScopes = database ? new TargetMigrationScopes({ pending: scope => scope.startsWith('historical:') }) : undefined;
|
|
54
|
+
if (database && migrationScopes)
|
|
55
|
+
context.resources.provide(pluginDataMigrationProviderToken, createSubscriptionTargetMigration({ database, scopes: migrationScopes }));
|
|
51
56
|
const outbound = context.resources.has(outboundHostToken) ? context.resources.use(outboundHostToken) : undefined;
|
|
52
57
|
let outboundPush = null;
|
|
53
58
|
if (outbound) {
|
|
54
59
|
outboundPush = async (input) => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
60
|
+
if (!input.target)
|
|
61
|
+
throw new DataMigrationError('unavailable', 'Historical RSS subscription awaits exact-target binding');
|
|
62
|
+
if (!outbound.sendTarget)
|
|
63
|
+
throw new Error('Canonical subscription delivery requires an exact-target Outbound Host');
|
|
64
|
+
const run = async () => { await outbound.sendTarget(input.target, input.content, { locale: input.locale }); };
|
|
65
|
+
if (migrationScopes)
|
|
66
|
+
await migrationScopes.run({ scope: subscriptionMigrationScope(input), run });
|
|
67
|
+
else
|
|
68
|
+
await run();
|
|
65
69
|
};
|
|
66
70
|
}
|
|
67
71
|
const runtime = Object.freeze({
|
|
68
72
|
db,
|
|
73
|
+
migrationScopes,
|
|
69
74
|
locale: resolveLocale(context.resources.use(projectLocaleToken)),
|
|
70
75
|
config: Object.freeze({ ...config }),
|
|
71
76
|
outbound: outboundPush,
|
package/src/channel.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { createDeliveryTarget, type DeliveryTarget, encodeTaskTarget, encodeStorageIdentity } from 'zhin.js/plugin-runtime';
|
|
1
2
|
import type { Locale } from 'zhin.js/i18n';
|
|
2
3
|
import { rssMessages as t } from './i18n.js';
|
|
3
4
|
/** A subscription destination uses public Message fields, never CapabilityId internals. */
|
|
4
5
|
|
|
5
6
|
export interface ChannelInfo {
|
|
7
|
+
readonly target: DeliveryTarget;
|
|
6
8
|
adapterName: string;
|
|
7
9
|
endpointKey: string;
|
|
8
10
|
channelType: 'private' | 'group' | 'channel';
|
|
@@ -39,15 +41,16 @@ export function extractChannelInfo(input: unknown): ChannelInfo | null {
|
|
|
39
41
|
const conversation = input.conversation;
|
|
40
42
|
const kind = conversation.kind;
|
|
41
43
|
if (kind !== 'private' && kind !== 'group' && kind !== 'channel') return null;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
const endpoint = isRecord(conversation.endpoint) ? conversation.endpoint : {};
|
|
45
|
+
if (!isIdentifier(endpoint.adapter) || !isIdentifier(endpoint.id) || !isIdentifier(conversation.id)) return null;
|
|
46
|
+
const target = createDeliveryTarget({ conversation: conversation as DeliveryTarget });
|
|
45
47
|
const sender = input.sender;
|
|
46
48
|
if (sender !== undefined && (!isRecord(sender) || !isIdentifier(sender.id))) return null;
|
|
47
49
|
|
|
48
50
|
return {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
target,
|
|
52
|
+
adapterName: target.endpoint.adapter,
|
|
53
|
+
endpointKey: target.endpoint.id,
|
|
51
54
|
channelType: kind,
|
|
52
55
|
channelId: conversation.id,
|
|
53
56
|
senderId: isRecord(sender) && isIdentifier(sender.id) ? sender.id : '',
|
|
@@ -58,8 +61,9 @@ export function extractChannelInfo(input: unknown): ChannelInfo | null {
|
|
|
58
61
|
/** Complete subscription scope, including the bot instance for multi-endpoint adapters. */
|
|
59
62
|
export function subscriptionScope(channel: ChannelInfo): Record<string, string> {
|
|
60
63
|
return {
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
target_json: JSON.stringify(encodeTaskTarget(channel.target)),
|
|
65
|
+
adapter_name: encodeStorageIdentity(channel.adapterName),
|
|
66
|
+
endpoint_id: encodeStorageIdentity(channel.endpointKey),
|
|
63
67
|
channel_type: channel.channelType,
|
|
64
68
|
channel_id: channel.channelId,
|
|
65
69
|
};
|
package/src/poll.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeTaskTarget } from 'zhin.js/plugin-runtime';
|
|
1
2
|
import { resolveLocale, type Locale } from 'zhin.js/i18n';
|
|
2
3
|
import { rssMessages as t } from './i18n.js';
|
|
3
4
|
/**
|
|
@@ -47,7 +48,13 @@ export interface CheckResult {
|
|
|
47
48
|
readonly pushed: number;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
interface RssFeedPushRequest {
|
|
52
|
+
readonly runtime: RssRuntime;
|
|
53
|
+
/** A single fetched feed, shared by this poll's subscribers without re-fetching. */
|
|
54
|
+
readonly feed: Readonly<{ url: string; title: string; items: FeedItem[] }>;
|
|
55
|
+
}
|
|
56
|
+
async function pushToSubscribers(input: RssFeedPushRequest): Promise<number> {
|
|
57
|
+
const { runtime, feed: { url: feedUrl, title: feedTitle, items } } = input;
|
|
51
58
|
const push = runtime.outbound;
|
|
52
59
|
const Subs = getRssSubs(runtime.db);
|
|
53
60
|
if (!push || !Subs) return 0;
|
|
@@ -63,7 +70,10 @@ async function pushToSubscribers(runtime: RssRuntime, feedUrl: string, feedTitle
|
|
|
63
70
|
|| typeof endpointKey !== 'string' || !endpointKey.trim()
|
|
64
71
|
|| (channelType !== 'private' && channelType !== 'group' && channelType !== 'channel')) continue;
|
|
65
72
|
try {
|
|
73
|
+
const target = sub.target_json == null ? undefined
|
|
74
|
+
: decodeTaskTarget(JSON.parse(String(sub.target_json)) as Record<string, unknown>);
|
|
66
75
|
await push({
|
|
76
|
+
...(target ? { target } : {}),
|
|
67
77
|
adapterName,
|
|
68
78
|
endpointKey,
|
|
69
79
|
channelType,
|
|
@@ -72,8 +82,8 @@ async function pushToSubscribers(runtime: RssRuntime, feedUrl: string, feedTitle
|
|
|
72
82
|
content: formatNewItems(feedTitle, items, runtime.config.maxItems, resolveLocale(sub.locale)),
|
|
73
83
|
});
|
|
74
84
|
pushed += 1;
|
|
75
|
-
} catch {
|
|
76
|
-
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.warn('[rss] subscription delivery failed:', error instanceof Error ? error.message : String(error));
|
|
77
87
|
}
|
|
78
88
|
}
|
|
79
89
|
return pushed;
|
|
@@ -112,7 +122,7 @@ export async function checkSubscriptions(runtime: RssRuntime, options: {
|
|
|
112
122
|
totalNew += newItems.length;
|
|
113
123
|
const body = formatNewItems(title || url, newItems, runtime.config.maxItems, locale);
|
|
114
124
|
parts.push(body);
|
|
115
|
-
pushed += await pushToSubscribers(runtime, url, title || url, newItems);
|
|
125
|
+
pushed += await pushToSubscribers({ runtime, feed: { url, title: title || url, items: newItems } });
|
|
116
126
|
} catch (e) {
|
|
117
127
|
parts.push(t(locale, 'checkFailed', { url, error: (e as Error).message }));
|
|
118
128
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DeliveryTarget, TargetMigrationScopes } from 'zhin.js/plugin-runtime';
|
|
1
2
|
import type { Locale } from 'zhin.js/i18n';
|
|
2
3
|
import { createToken } from 'zhin.js';
|
|
3
4
|
import type { RssConfig } from './feed.js';
|
|
@@ -5,6 +6,8 @@ import type { RssMemoryDb } from './memory-store.js';
|
|
|
5
6
|
import type { ChannelInfo } from './channel.js';
|
|
6
7
|
|
|
7
8
|
export type RssOutboundPush = (input: {
|
|
9
|
+
/** Explicit canonical target on new records; absent only at the pending historical-data boundary. */
|
|
10
|
+
readonly target?: DeliveryTarget;
|
|
8
11
|
readonly adapterName: string;
|
|
9
12
|
readonly endpointKey: string;
|
|
10
13
|
readonly channelType: ChannelInfo['channelType'];
|
|
@@ -14,6 +17,7 @@ export type RssOutboundPush = (input: {
|
|
|
14
17
|
}) => Promise<void>;
|
|
15
18
|
|
|
16
19
|
export interface RssRuntime {
|
|
20
|
+
readonly migrationScopes?: TargetMigrationScopes;
|
|
17
21
|
readonly locale?: Locale;
|
|
18
22
|
readonly db: RssMemoryDb;
|
|
19
23
|
readonly config: Readonly<RssConfig>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { conversationRefKey } from 'zhin.js';
|
|
2
|
+
import {
|
|
3
|
+
createRelationalTargetMigration,
|
|
4
|
+
decodeTaskTarget,
|
|
5
|
+
encodeStorageIdentity,
|
|
6
|
+
encodeTaskTarget,
|
|
7
|
+
orderedMigrationRows,
|
|
8
|
+
targetMigrationDigest,
|
|
9
|
+
type DeliveryTarget,
|
|
10
|
+
type PluginDatabaseHost,
|
|
11
|
+
type PluginDataMigrationProvider,
|
|
12
|
+
type TargetMigrationScopes,
|
|
13
|
+
} from 'zhin.js/plugin-runtime';
|
|
14
|
+
|
|
15
|
+
/** Chat subscriptions use exact targets; historical selectors are inventory facts only. */
|
|
16
|
+
export function subscriptionMigrationScope(
|
|
17
|
+
input: Readonly<{
|
|
18
|
+
target?: DeliveryTarget;
|
|
19
|
+
adapterName: string;
|
|
20
|
+
endpointKey: string;
|
|
21
|
+
channelType: string;
|
|
22
|
+
channelId: string;
|
|
23
|
+
}>,
|
|
24
|
+
): string {
|
|
25
|
+
return input.target
|
|
26
|
+
? `canonical:${conversationRefKey(input.target)}`
|
|
27
|
+
: `historical:${targetMigrationDigest({
|
|
28
|
+
adapter_name: input.adapterName,
|
|
29
|
+
endpoint_id: input.endpointKey,
|
|
30
|
+
channel_type: input.channelType,
|
|
31
|
+
channel_id: input.channelId,
|
|
32
|
+
})}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function createSubscriptionTargetMigration(
|
|
36
|
+
input: Readonly<{ database: PluginDatabaseHost; scopes: TargetMigrationScopes }>,
|
|
37
|
+
): PluginDataMigrationProvider {
|
|
38
|
+
const table = 'rss_subscriptions';
|
|
39
|
+
return createRelationalTargetMigration({
|
|
40
|
+
...input,
|
|
41
|
+
domain: 'rss',
|
|
42
|
+
title: 'RSS subscription destinations',
|
|
43
|
+
sourceVersion: 'subscription-alias-v0',
|
|
44
|
+
tables: [table],
|
|
45
|
+
async readUnits(reader) {
|
|
46
|
+
const rows = await reader.model(table).select();
|
|
47
|
+
const grouped = new Map<string, { query: Record<string, unknown>; rows: Record<string, unknown>[] }>();
|
|
48
|
+
for (const row of rows) {
|
|
49
|
+
const query = {
|
|
50
|
+
adapter_name: row.adapter_name,
|
|
51
|
+
endpoint_id: row.endpoint_id,
|
|
52
|
+
channel_type: row.channel_type,
|
|
53
|
+
channel_id: row.channel_id,
|
|
54
|
+
target_json: row.target_json ?? null,
|
|
55
|
+
};
|
|
56
|
+
const id = targetMigrationDigest(query);
|
|
57
|
+
const unit: { query: Record<string, unknown>; rows: Record<string, unknown>[] } = grouped.get(id) ?? {
|
|
58
|
+
query,
|
|
59
|
+
rows: [],
|
|
60
|
+
};
|
|
61
|
+
unit.rows.push(row);
|
|
62
|
+
grouped.set(id, unit);
|
|
63
|
+
}
|
|
64
|
+
return [...grouped.entries()]
|
|
65
|
+
.map(([id, unit]) => {
|
|
66
|
+
let target: DeliveryTarget | undefined,
|
|
67
|
+
status: 'canonical' | 'unresolved' | 'corrupt' = 'unresolved';
|
|
68
|
+
if (unit.query.target_json !== null) {
|
|
69
|
+
try {
|
|
70
|
+
target = decodeTaskTarget(JSON.parse(String(unit.query.target_json)));
|
|
71
|
+
status = 'canonical';
|
|
72
|
+
} catch {
|
|
73
|
+
status = 'corrupt';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const selectors = {
|
|
77
|
+
adapterName: String(unit.query.adapter_name),
|
|
78
|
+
endpointKey: String(unit.query.endpoint_id),
|
|
79
|
+
channelType: String(unit.query.channel_type),
|
|
80
|
+
channelId: String(unit.query.channel_id),
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
id,
|
|
84
|
+
title: `RSS: ${selectors.channelType}/${selectors.channelId}`,
|
|
85
|
+
status,
|
|
86
|
+
scope: subscriptionMigrationScope({ ...selectors, ...(target ? { target } : {}) }),
|
|
87
|
+
records: [{ table, query: unit.query, rows: orderedMigrationRows(unit.rows) }],
|
|
88
|
+
summary: { ...selectors, duplicateRows: unit.rows.length },
|
|
89
|
+
};
|
|
90
|
+
})
|
|
91
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
92
|
+
},
|
|
93
|
+
rewrite(unit, target) {
|
|
94
|
+
const before = unit.records[0]!;
|
|
95
|
+
const patch = {
|
|
96
|
+
target_json: JSON.stringify(encodeTaskTarget(target)),
|
|
97
|
+
adapter_name: encodeStorageIdentity(target.endpoint.adapter),
|
|
98
|
+
endpoint_id: encodeStorageIdentity(target.endpoint.id),
|
|
99
|
+
channel_type: target.kind,
|
|
100
|
+
channel_id: target.id,
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
destinationScope: subscriptionMigrationScope({
|
|
104
|
+
target,
|
|
105
|
+
adapterName: target.endpoint.adapter,
|
|
106
|
+
endpointKey: target.endpoint.id,
|
|
107
|
+
channelType: target.kind,
|
|
108
|
+
channelId: target.id,
|
|
109
|
+
}),
|
|
110
|
+
writes: [
|
|
111
|
+
{ before, after: { table, query: patch, rows: before.rows.map((row) => ({ ...row, ...patch })) }, patch },
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
}
|