@geoly-ai/social-hub-sdk 0.0.56 → 0.0.57

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
@@ -67,6 +67,12 @@ export type ListCalendarEntriesParams = {
67
67
  export type UpdateCalendarEntryBody = {
68
68
  plannedAt?: string;
69
69
  status?: string;
70
+ /**
71
+ * 「谁来发这条内容」——防重复发帖的唯一闸门(方案 Block 0 · D1)。
72
+ * 改它会让服务端在同一事务里撤销/创建内部 job 并 append directive 指令,
73
+ * 因此这是**高风险写**,CLI 侧带 `--apply` 门。见 {@link CalendarEntryDeliveryMode}。
74
+ */
75
+ deliveryMode?: CalendarEntryDeliveryMode;
70
76
  permalink?: string;
71
77
  failureReason?: string;
72
78
  };
@@ -1048,6 +1054,14 @@ export declare class SocialHubClient {
1048
1054
  }): Promise<{
1049
1055
  metrics?: Record<string, number | undefined>;
1050
1056
  }>;
1057
+ /**
1058
+ * `GET .../calendar-entries` 的 URL —— {@link SocialHubClient.listCalendarEntries}
1059
+ * 与 {@link SocialHubClient.listCalendarEntriesTyped} 共用。
1060
+ *
1061
+ * 抽出来是为了让两个方法**不可能**漂移:将来加一个过滤参数只改一处,
1062
+ * 否则 typed 变体会静默少一个过滤条件,表现为「同样的参数却多返回了行」。
1063
+ */
1064
+ private calendarEntriesUrl;
1051
1065
  listCalendarEntries(teamId: string, params?: ListCalendarEntriesParams): Promise<{
1052
1066
  items: unknown[];
1053
1067
  }>;
@@ -1055,6 +1069,39 @@ export declare class SocialHubClient {
1055
1069
  ok: boolean;
1056
1070
  warning?: string;
1057
1071
  }>;
1072
+ /**
1073
+ * 与 {@link SocialHubClient.listCalendarEntries} **同一个端点**,只是把返回体
1074
+ * 标成 {@link CalendarEntryListItemDto}。
1075
+ *
1076
+ * 为什么另开一个方法而不是收紧旧方法的返回类型:旧方法返回 `unknown[]`,既有调用方
1077
+ * 普遍在外面自己 `as` 成本地形状;把它改成具名类型会让那些断言从「无操作」变成
1078
+ * 「类型不兼容」,是一次纯粹为了好看的破坏性变更。新方法零风险,想要
1079
+ * `deliveryMode` / `directiveRevision` 的调用方直接用它。
1080
+ *
1081
+ * ⚠️ 运行时**不做校验**(SDK 不引 zod):老服务端不会回这两个字段,所以它们在
1082
+ * DTO 里是可选的——读到 `undefined` 一律按 `hub_managed` / 未知 revision 处理,
1083
+ * 不要当成 0。
1084
+ */
1085
+ listCalendarEntriesTyped(teamId: string, params?: ListCalendarEntriesParams): Promise<{
1086
+ items: CalendarEntryListItemDto[];
1087
+ }>;
1088
+ /**
1089
+ * GET .../publishing-calendar-directives/:calendarEntryId/preflight?revision=N
1090
+ * —— 外部 agent 的 cron 到点后、**真正发帖前**必须调的只读校验(方案 §8 D5)。
1091
+ *
1092
+ * 这是整条链路上正文的**唯一出口**:directive 事件 payload 里只有身份 + 版本号。
1093
+ * 服务端在同一个只读快照里确认「条目仍 scheduled / 仍 external_agent / revision 仍是
1094
+ * 你手上那条 / 审核仍 passed」,四条全成立才把内容交出来。
1095
+ *
1096
+ * ⚠️ **业务拒绝是 HTTP 200 + `decision: "rejected"`,不是 4xx**——本方法不会为
1097
+ * `rejected` 抛错。调用方必须显式判 `decision`;`if (await preflight(...))` 这种写法
1098
+ * 会把每一次拒绝都当成放行。4xx/5xx 只留给请求本身或系统的错误。
1099
+ *
1100
+ * `revision` 必须是调用方手上那条 directive 的版本号,**不能省、不能猜**:服务端
1101
+ * 拒绝空值与非数字,而 revision 0 是每条条目的合法初始值,任何「默认值」都会放行
1102
+ * 真实条目。这里先在客户端挡一道,免得把明显非法的值打到网络上。
1103
+ */
1104
+ preflightPublishingCalendarDirective(teamId: string, calendarEntryId: string, revision: number): Promise<PublishingCalendarPreflightResultDto>;
1058
1105
  /**
1059
1106
  * 归属桶(teams.kind='bucket':未配置/外部)。这些团队没有 membership、不出现
1060
1107
  * 在 `listTeams()` 里,所以外部来源帖要回填进桶就只能先从这里拿到 UUID,
@@ -3597,5 +3644,145 @@ export type NotificationPullResponseDto = {
3597
3644
  * 与 contracts `compareNotificationSeq` 同口径;SDK 侧复刻是因为不能引 contracts。
3598
3645
  */
3599
3646
  export declare function compareNotificationSeqStrings(left: string, right: string): number;
3647
+ /**
3648
+ * 这条日历条目由谁发布 —— **防重复发帖的唯一闸门**(方案 D1)。
3649
+ * - `hub_managed`(默认):Hub 同事务建内部 `publish_post` job,自己发;**不**产生指令事件。
3650
+ * - `external_agent`:**不**建内部 job,改由 `publishing-calendar-directive.v1` 事件
3651
+ * 驱动用户自己机器上的 agent 建 UTC 一次性 cron 去发。
3652
+ *
3653
+ * 两者互斥。老服务端不回这个字段 —— 读到 `undefined` 按 `hub_managed` 处理。
3654
+ */
3655
+ export type CalendarEntryDeliveryMode = "hub_managed" | "external_agent";
3656
+ /** 指令变体:期望状态是「该有一个 cron」还是「不该有」。 */
3657
+ export type PublishingCalendarDirectiveKind = "upsert" | "cancel";
3658
+ /** cancel 的原因(枚举而非自由文本:agent 按它分流告警 vs 正常运营动作)。 */
3659
+ export type PublishingCalendarDirectiveCancelReason =
3660
+ /** 运营主动取消这条日历条目。 */
3661
+ "entry_cancelled"
3662
+ /** 条目行被删除(含 plan/account 级联)。 */
3663
+ | "entry_deleted"
3664
+ /** 审核由 passed 回退,内容不再允许发布。 */
3665
+ | "review_revoked"
3666
+ /** 条目改回 `hub_managed`,改由 Hub 内部发布。 */
3667
+ | "delivery_mode_changed"
3668
+ /** 关联草稿被解绑(`content_draft_id SET NULL`)。 */
3669
+ | "draft_detached";
3670
+ /**
3671
+ * preflight 的拒绝原因。**每一条都必须有本地处置动作**,不能笼统当成「失败重试」——
3672
+ * 其中大部分是终态(该删 cron),轮询重试只会把一条已经不该发的内容一直挂着。
3673
+ */
3674
+ export type PublishingCalendarPreflightRejectionReason =
3675
+ /** 条目不存在、不属于本 team,或调用方品牌作用域看不到它。此时 `currentRevision` 恒为 null。 */
3676
+ "entry_not_found"
3677
+ /** 条目已不是 `scheduled`(取消/发布中/已发/失败)。删 cron。 */
3678
+ | "entry_not_scheduled"
3679
+ /** 条目已改回 `hub_managed`,Hub 自己发。删 cron。 */
3680
+ | "delivery_mode_not_external"
3681
+ /** 手上的 revision 比 Hub 当前的旧 —— 还有一条更新的指令在路上。 */
3682
+ | "revision_stale"
3683
+ /** 手上的 revision 比 Hub 当前的**新**。正常不该发生,一律不给内容。 */
3684
+ | "revision_unknown"
3685
+ /** 条目没绑草稿,或草稿行已不在。 */
3686
+ | "draft_detached"
3687
+ /** 当前草稿的 canonical review target 不存在、身份漂移,或状态不是 `passed`。 */
3688
+ | "review_not_passed";
3689
+ /** preflight 放行:**唯一**能拿到正文的分支。 */
3690
+ export type PublishingCalendarPreflightOkDto = {
3691
+ decision: "ok";
3692
+ calendarEntryId: string;
3693
+ publishingPlanId: string;
3694
+ /** 服务端当前 revision(ok 时必然 === 请求里那个)。 */
3695
+ revision: number;
3696
+ socialAccountId: string;
3697
+ subreddit: string;
3698
+ /** **Z 结尾的 UTC**;直接拿去建 UTC one-shot cron,不要先转本地时区。 */
3699
+ plannedAt: string;
3700
+ content: {
3701
+ contentDraftId: string;
3702
+ contentDraftVersion: number;
3703
+ title: string;
3704
+ body: string;
3705
+ };
3706
+ review: {
3707
+ targetId: string;
3708
+ /** 恒为 `passed` —— 没有第二种 ok。 */
3709
+ status: "passed";
3710
+ /** 服务端 canonical 内容 hash,可留痕对账。 */
3711
+ contentHash: string;
3712
+ };
3713
+ };
3714
+ export type PublishingCalendarPreflightRejectedDto = {
3715
+ decision: "rejected";
3716
+ calendarEntryId: string;
3717
+ reason: PublishingCalendarPreflightRejectionReason;
3718
+ /**
3719
+ * Hub 当前的 revision,**仅供诊断对账**。
3720
+ *
3721
+ * 🔴 绝不能拿它推进本地的「已见最高 revision」:收到 rev 5 的 cron 被判
3722
+ * `revision_stale/currentRevision=6` 后若把本地状态升到 6,随后真正到达的 rev 6
3723
+ * `upsert` 会被当成旧消息忽略 —— 结果是**一个 cron 都没有**。只等真实的指令。
3724
+ *
3725
+ * `entry_not_found` 时恒为 null(那个 reason 同时覆盖「真不存在」与「作用域看不到」)。
3726
+ */
3727
+ currentRevision: number | null;
3728
+ };
3729
+ /**
3730
+ * preflight 判定结果。**业务拒绝走 200 + 本判别联合,不用 404/409**:
3731
+ * cron 路径要能无歧义分流每个 reason。判 `decision` 之前不要碰任何字段。
3732
+ */
3733
+ export type PublishingCalendarPreflightResultDto = PublishingCalendarPreflightOkDto | PublishingCalendarPreflightRejectedDto;
3734
+ /**
3735
+ * `GET .../calendar-entries` 的行形状(含 joined labels)。
3736
+ *
3737
+ * 只被 {@link SocialHubClient.listCalendarEntriesTyped} 使用;旧的
3738
+ * `listCalendarEntries` 仍返回 `unknown[]`,故意不动。
3739
+ */
3740
+ export type CalendarEntryListItemDto = {
3741
+ id: string;
3742
+ teamId: string;
3743
+ publishingPlanId: string;
3744
+ brandId: string;
3745
+ /** legacy;brand-first 建的计划为 null。 */
3746
+ campaignId: string | null;
3747
+ contentDraftId: string | null;
3748
+ socialAccountId: string;
3749
+ subreddit: string;
3750
+ plannedAt: string;
3751
+ status: CalendarEntryStatus;
3752
+ /** 见 {@link CalendarEntryDeliveryMode};老数据/老服务端缺省视为 `hub_managed`。 */
3753
+ deliveryMode?: CalendarEntryDeliveryMode;
3754
+ /**
3755
+ * 单调递增的指令版本,**高版本覆盖低版本**。只对 `external_agent` 有业务意义,
3756
+ * 但 `hub_managed` 也照常递增(改回外部时不会倒退)。缺省 = 老服务端,不是 0。
3757
+ */
3758
+ directiveRevision?: number;
3759
+ publishedAt: string | null;
3760
+ permalink: string | null;
3761
+ failureReason: string | null;
3762
+ createdAt: string;
3763
+ /** 迁移 0149 起维护;更早的真实修改时间已不可考。 */
3764
+ updatedAt?: string;
3765
+ brandName: string;
3766
+ campaignName: string | null;
3767
+ socialAccountHandle: string | null;
3768
+ socialAccountPlatform: string;
3769
+ draftTitle: string | null;
3770
+ draftExcerpt: string | null;
3771
+ reviewGate?: {
3772
+ targetId: string | null;
3773
+ status: ReviewTargetStatus | null;
3774
+ contentVersion: number | null;
3775
+ /** target 是否对应当前草稿版本(canonical 全校验)。 */
3776
+ isCurrent: boolean;
3777
+ gateState: ReviewGateState;
3778
+ lastError: string | null;
3779
+ } | null;
3780
+ };
3781
+ /** 契约 `calendarEntryStatusSchema` 的镜像。 */
3782
+ export type CalendarEntryStatus = "draft" | "scheduled" | "exported" | "running" | "succeeded" | "failed" | "cancelled";
3783
+ /** 契约 `reviewTargetStatusSchema` 的镜像(审核 target 的原生状态)。 */
3784
+ export type ReviewTargetStatus = "pending" | "running" | "passed" | "needs_revision" | "blocked" | "degraded" | "superseded";
3785
+ /** 契约 `reviewGateStateSchema` 的镜像(日历条目上的审核门投影)。 */
3786
+ export type ReviewGateState = "passed" | "waiting" | "revision_required" | "blocked" | "stale" | "untracked";
3600
3787
  export {};
3601
3788
  //# sourceMappingURL=index.d.ts.map