@geoly-ai/social-hub-sdk 0.1.14 → 0.1.16

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/dist/index.d.ts CHANGED
@@ -722,6 +722,22 @@ export type ListSubredditWatchlistsParams = {
722
722
  campaignId?: string;
723
723
  /** 按板块名精确查归属(r/ 前缀可省,大小写不敏感)。 */
724
724
  subreddit?: string;
725
+ /** 板块名**子串**搜索(大小写不敏感,r/ 可省);与 `subreddit` 是两个独立谓词。 */
726
+ subredditQuery?: string;
727
+ /** ⚠️ 2026-09-09 之前本 SDK 方法**漏传**了服务端早就支持的 status/brandId/industryKeys。 */
728
+ status?: "active" | "paused" | "archived";
729
+ brandId?: string;
730
+ /** 逗号分隔的行业 key 列表(服务端自己 split)。 */
731
+ industryKeys?: string;
732
+ tag?: string;
733
+ /**
734
+ * 新帖监听状态。软停语义:`disabled` = 停过(配置行还在),`never` = 从没加过。
735
+ * ⚠️ 受限主体(client)传这个会 403 —— 监听是系统级运维配置。
736
+ */
737
+ monitorState?: "enabled" | "disabled" | "never";
738
+ /** ⚠️ `monitorLastObservedAt` 与 `monitorState` 同一道权限门。 */
739
+ sortBy?: "createdAt" | "subreddit" | "monitorLastObservedAt";
740
+ sortDir?: "asc" | "desc";
725
741
  };
726
742
  export type ListSubredditMonitorsParams = {
727
743
  limit?: number;
@@ -756,12 +772,30 @@ export type SubredditMonitorRuleScope = "title" | "body" | "both";
756
772
  * ⚠️ CJK 没有词边界概念,`word` 在 CJK 上退化为子串 —— 否则「咖啡」永远匹配不上「咖啡机」。
757
773
  */
758
774
  export type SubredditMonitorMatchMode = "word" | "substring" | "phrase";
775
+ /**
776
+ * 规则极性(0171)。
777
+ * - `include`:命中它就算相关;
778
+ * - `exclude`:命中它就**撤销**同等或更低来源优先级的 include 命中
779
+ * (优先级 manual > brand_keyword > expansion —— 模型扩出来的否定词不该把运营
780
+ * 亲手填的 include 词否掉)。
781
+ *
782
+ * ⚠️ exclude 规则**自己不产生命中**。一条 include 都没有的规则集会被服务端拒绝激活
783
+ *(409)—— 那等于把整个板块静音,而卡片上看起来只是「今天没有相关新帖」。
784
+ * ⚠️ 同一个 (term, scope, matchMode) 上**可以**同时存在 include 与 exclude 两条:
785
+ *「espresso 收进来、espresso martini 排出去」正是这个形状。
786
+ */
787
+ export type SubredditMonitorRulePolarity = "include" | "exclude";
759
788
  export type SubredditMonitorKeywordRuleInput = {
760
789
  /** 原样字面值;服务端归一化(NFKC / 去重音 / 小写)后才进唯一键。 */
761
790
  term: string;
762
791
  scope?: SubredditMonitorRuleScope;
763
792
  matchMode?: SubredditMonitorMatchMode;
764
- /** 只影响卡片里命中词的展示顺序,不影响是否命中(本期只做 include)。 */
793
+ /** 省略 = `include`。见 {@link SubredditMonitorRulePolarity}。 */
794
+ polarity?: SubredditMonitorRulePolarity;
795
+ /**
796
+ * 影响卡片里命中词的展示顺序;对 exclude 规则则决定「因为 X 被排除」里 X 的排序。
797
+ * ⚠️ 它**不是**打分阈值:命中与否是布尔判定,不存在「权重不够就不算命中」。
798
+ */
765
799
  weight?: number;
766
800
  /** 品牌词导入的**来源溯源**;⛔ 不建立同步语义。 */
767
801
  sourceBrandKeywordId?: string | null;
@@ -772,13 +806,89 @@ export type SubredditMonitorKeywordRule = Required<Pick<SubredditMonitorKeywordR
772
806
  ruleSetId: string;
773
807
  normalizedTerm: string;
774
808
  scope: SubredditMonitorRuleScope;
775
- /** 本期只有 `include`(排除词是 P2,契约与 DDL 层都表达不出来)。 */
776
- polarity: "include";
809
+ /** `include` / `exclude`(0171 起)。见 {@link SubredditMonitorRulePolarity}。 */
810
+ polarity: SubredditMonitorRulePolarity;
777
811
  matchMode: SubredditMonitorMatchMode;
778
812
  weight: number;
779
813
  sourceBrandKeywordId: string | null;
780
814
  sourceBrandKeywordValue: string | null;
781
815
  };
816
+ /**
817
+ * 回放的逐帖判定。
818
+ * 🔴 `excluded` 与 `no_match` 是**两个不同的值**,⛔ 不得合并:
819
+ * `excluded` = 命中了 include 但被排除词否掉(去看排除词是不是配宽了);
820
+ * `no_match` = 一个 include 都没命中(去看 include 词是不是配窄了)。
821
+ */
822
+ export type SubredditMonitorReplayDecision = "matched" | "indeterminate" | "excluded" | "no_match";
823
+ export type SubredditMonitorReplayRun = {
824
+ id: string;
825
+ monitorId: string;
826
+ ruleSetId: string;
827
+ ruleSetVersion: number | null;
828
+ ruleHash: string | null;
829
+ windowStart: string;
830
+ windowEnd: string;
831
+ evaluatedCount: number;
832
+ matchedCount: number;
833
+ indeterminateCount: number;
834
+ /** 命中了 include 但被排除词否掉。⛔ 不含在 screenedOutCount 里。 */
835
+ excludedCount: number;
836
+ screenedOutCount: number;
837
+ /** 撞上硬顶。⚠️ **是布尔不是计数** —— 查询给不出准确的剩余数。 */
838
+ truncated: boolean;
839
+ note: string | null;
840
+ requestedBy: string | null;
841
+ createdAt: string;
842
+ };
843
+ export type SubredditMonitorReplayHit = {
844
+ id: string;
845
+ canonicalPermalink: string;
846
+ title: string | null;
847
+ postedAt: string | null;
848
+ decision: SubredditMonitorReplayDecision;
849
+ matchedTerms: string[];
850
+ matchedScopes: string[];
851
+ totalWeight: number;
852
+ bodyAvailability: string;
853
+ /** 造成撤销的排除词。`decision='excluded'` 时非空。 */
854
+ excludedByTerms: string[];
855
+ /** 正文拿不到 + 有正文域 exclude 规则 ⇒「该不该排除」判不了。 */
856
+ exclusionIndeterminate: boolean;
857
+ /** 当时**真实**账本里的判定;null = 当时没有账本行(见 originalAbsentReason)。 */
858
+ originalDecision: "matched" | "indeterminate" | null;
859
+ originalReportedAt: string | null;
860
+ originalRuleSetId: string | null;
861
+ /**
862
+ * 🔴 `originalDecision === null` 是多义的,这一位把它拆开:
863
+ * `screened_out` = 当时确实见过、只是判了不命中(账本对不命中一条都不写);
864
+ * `never_observed` = 当时根本没见过(还没开监听 / VOC 回灌进来的)。
865
+ * ⛔ 合并成「原来没报」会让「监听那时还没开」被误读成「规则漏了」。
866
+ */
867
+ originalAbsentReason: "screened_out" | "never_observed" | null;
868
+ };
869
+ export type SubredditMonitorReplayRunDetail = SubredditMonitorReplayRun & {
870
+ subreddit: string;
871
+ ruleSetStatus: "draft" | "active" | "retired";
872
+ /** 与真实账本的差分 —— 回放的产品价值就在这里。 */
873
+ diff: {
874
+ /** 当初报过、按新规则不再报的条数。 */
875
+ wouldStopReporting: number;
876
+ /**
877
+ * 当初被筛掉、按新规则会报的条数。
878
+ * ⚠️ 分母**只算** `screened_out`,⛔ 不含 `never_observed`
879
+ *(那是「监听那时还没开」,不是规则的功劳)。
880
+ */
881
+ wouldNewlyReport: number;
882
+ /** 当时根本没被这个监听观察到的条数。⛔ 不是「规则漏了」。 */
883
+ neverObserved: number;
884
+ };
885
+ /** 🔴 显式的副作用边界声明:回放没通知任何人、没改账本、没推进水位。 */
886
+ sideEffects: {
887
+ notificationsSent: 0;
888
+ hitsLedgerWritten: false;
889
+ reportedWatermarkAdvanced: false;
890
+ };
891
+ };
782
892
  export type SubredditMonitorRuleSet = {
783
893
  id: string;
784
894
  monitorId: string;
@@ -2731,6 +2841,27 @@ export declare class SocialHubClient {
2731
2841
  activated: SubredditMonitorRuleSetDetail;
2732
2842
  retiredRuleSetId: string | null;
2733
2843
  }>;
2844
+ runSubredditMonitorReplay(monitorId: string, body: {
2845
+ /** 省略 = 该监听当前 active 的那版。可显式传 draft(主要用法)。 */
2846
+ ruleSetId?: string;
2847
+ /** ISO 时间串或 Date;窗口按帖子的 postedAt 取,左闭右开,最长 30 天。 */
2848
+ windowStart: string | Date;
2849
+ windowEnd: string | Date;
2850
+ /** 硬顶(默认 500,最大 2000)。撞顶时结果 `truncated=true`。 */
2851
+ limit?: number;
2852
+ note?: string | null;
2853
+ }): Promise<SubredditMonitorReplayRunDetail>;
2854
+ listSubredditMonitorReplays(monitorId: string, params?: {
2855
+ limit?: number;
2856
+ }): Promise<{
2857
+ items: SubredditMonitorReplayRun[];
2858
+ }>;
2859
+ getSubredditMonitorReplay(monitorId: string, replayRunId: string, params?: {
2860
+ decision?: SubredditMonitorReplayDecision;
2861
+ limit?: number;
2862
+ }): Promise<SubredditMonitorReplayRun & {
2863
+ results: SubredditMonitorReplayHit[];
2864
+ }>;
2734
2865
  /** 停用当前版本 ⇒ 该监听回到「不设关键词门」,报告**恢复全量新帖**。 */
2735
2866
  retireSubredditMonitorRuleSet(monitorId: string, ruleSetId: string): Promise<{
2736
2867
  ok: boolean;