@zhin.js/plugin-rss 1.1.12 → 1.1.13

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.
@@ -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 cfg = resolveRssConfig(config);
26
- const existing = await Subs.select().where({
27
- url,
28
- ...subscriptionScope(channel),
29
- });
30
- if (existing.length > 0)
31
- return t(locale, 'existing');
32
- const currentSubs = await Subs.select().where({
33
- ...subscriptionScope(channel),
34
- });
35
- if (currentSubs.length >= cfg.maxPerGroup) {
36
- return t(locale, 'limit', { max: cfg.maxPerGroup });
37
- }
38
- let feedTitle = '';
39
- try {
40
- const { title, items } = await fetchFeed(url, cfg.timeout);
41
- feedTitle = title;
42
- await markItemsSeen(runtime, url, items);
43
- }
44
- catch (e) {
45
- return t(locale, 'loadFailed', { error: e.message });
46
- }
47
- await Subs.insert({
48
- url,
49
- feed_title: feedTitle,
50
- adapter_name: channel.adapterName,
51
- endpoint_id: channel.endpointKey,
52
- channel_type: channel.channelType,
53
- channel_id: channel.channelId,
54
- creator_id: channel.senderId,
55
- creator_name: channel.senderName,
56
- created_at: new Date().toISOString(),
57
- locale,
58
- });
59
- return t(locale, 'added', { feed: feedTitle || url });
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 cfg = resolveRssConfig(config);
24
-
25
- const existing = await Subs.select().where({
26
- url,
27
- ...subscriptionScope(channel),
28
- });
29
- if (existing.length > 0) return t(locale, 'existing');
30
-
31
- const currentSubs = await Subs.select().where({
32
- ...subscriptionScope(channel),
33
- });
34
- if (currentSubs.length >= cfg.maxPerGroup) {
35
- return t(locale, 'limit', { max: cfg.maxPerGroup });
36
- }
37
-
38
- let feedTitle = '';
39
- try {
40
- const { title, items } = await fetchFeed(url, cfg.timeout);
41
- feedTitle = title;
42
- await markItemsSeen(runtime, url, items);
43
- } catch (e) {
44
- return t(locale, 'loadFailed', { error: (e as Error).message });
45
- }
46
-
47
- await Subs.insert({
48
- url,
49
- feed_title: feedTitle,
50
- adapter_name: channel.adapterName,
51
- endpoint_id: channel.endpointKey,
52
- channel_type: channel.channelType,
53
- channel_id: channel.channelId,
54
- creator_id: channel.senderId,
55
- creator_name: channel.senderName,
56
- created_at: new Date().toISOString(),
57
- locale,
58
- });
59
-
60
- return t(locale, 'added', { feed: feedTitle || url });
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 Subs = getRssSubs(use(rssRuntimeToken).db);
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 rows = await Subs.select().where({
21
- url,
22
- ...subscriptionScope(channel),
23
- });
24
- if (rows.length === 0)
25
- return t(locale, 'notFound');
26
- const row = rows[0];
27
- // 表结构没有 id 列,删除必须按业务键匹配(与上面的 select 条件一致)。
28
- await Subs.delete().where({
29
- url,
30
- ...subscriptionScope(channel),
31
- });
32
- return t(locale, 'removed', { feed: String(row.feed_title || url) });
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 Subs = getRssSubs(use(rssRuntimeToken).db);
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 rows = await Subs.select().where({
21
- url,
22
- ...subscriptionScope(channel),
23
- });
22
+ const run = async () => {
23
+ const rows = await Subs.select().where({
24
+ url,
25
+ ...subscriptionScope(channel),
26
+ });
24
27
 
25
- if (rows.length === 0) return t(locale, 'notFound');
28
+ if (rows.length === 0) return t(locale, 'notFound');
26
29
 
27
- const row = rows[0]!;
28
- // 表结构没有 id 列,删除必须按业务键匹配(与上面的 select 条件一致)。
29
- await Subs.delete().where({
30
- url,
31
- ...subscriptionScope(channel),
32
- });
33
- return t(locale, 'removed', { feed: String(row.feed_title || url) });
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';
@@ -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,CAoBrE;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAO9E"}
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
- if (!isIdentifier(input.clientAdapter) || !isIdentifier(input.endpointId)
29
- || !isIdentifier(conversation.id))
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
- adapterName: input.clientAdapter,
36
- endpointKey: input.endpointId,
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
- adapter_name: channel.adapterName,
47
- endpoint_id: channel.endpointKey,
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
  };
@@ -1 +1 @@
1
- {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
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":"AAAA,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;AAkCD;;;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"}
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(runtime, feedUrl, feedTitle, items) {
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
- // OutboundHost already logs; continue other subscribers.
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":"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"}
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>;
@@ -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"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAqBtC,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CACxC,kBAAkB,EAClB,0BAA0B,CAC3B,CAAC"}
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.12",
3
+ "version": "1.1.13",
4
4
  "description": "RSS/Atom feed subscription plugin for Zhin.js (Plugin Runtime)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -42,19 +42,19 @@
42
42
  "dependencies": {
43
43
  "rss-parser": "^3.13.0",
44
44
  "@zhin.js/im-contract": "1.1.9",
45
- "@zhin.js/tool": "1.1.12",
46
- "@zhin.js/skill": "1.1.10"
45
+ "@zhin.js/tool": "1.1.13",
46
+ "@zhin.js/skill": "1.1.11"
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.18"
52
+ "zhin.js": "1.1.19"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "zod": "^4.0.0",
56
- "@zhin.js/command": "^1.1.11",
57
- "zhin.js": "^1.1.18"
56
+ "@zhin.js/command": "^1.1.12",
57
+ "zhin.js": "^1.1.19"
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
- await outbound.send({
56
- adapter: input.adapterName,
57
- endpointKey: input.endpointKey,
58
- conversation: {
59
- kind: input.channelType,
60
- id: input.channelId,
61
- },
62
- content: input.content,
63
- locale: input.locale,
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
- if (!isIdentifier(input.clientAdapter) || !isIdentifier(input.endpointId)
43
- || !isIdentifier(conversation.id)) return null;
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
- adapterName: input.clientAdapter,
50
- endpointKey: input.endpointId,
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
- adapter_name: channel.adapterName,
62
- endpoint_id: channel.endpointKey,
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
- async function pushToSubscribers(runtime: RssRuntime, feedUrl: string, feedTitle: string, items: FeedItem[]): Promise<number> {
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
- // OutboundHost already logs; continue other subscribers.
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
+ }