@geoly-ai/social-hub-sdk 0.0.54 → 0.0.56
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 +240 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +93 -0
- package/dist/index.test.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -759,6 +759,79 @@ export type ListReportsParams = {
|
|
|
759
759
|
limit?: number;
|
|
760
760
|
reportType?: "reddit-post-snapshot" | "account-status-snapshot" | "campaign-digest" | "agent-run-summary" | "style-curation-report" | "quota-violation-report" | "content-weekly";
|
|
761
761
|
};
|
|
762
|
+
/** `user_feishu_identities.resolve_status`(迁移 0144)。 */
|
|
763
|
+
export type FeishuIdentityResolveStatus = "resolved" | "not_found" | "lookup_failed";
|
|
764
|
+
/**
|
|
765
|
+
* 列表过滤值。比 {@link FeishuIdentityResolveStatus} 多一个 `unmapped` ——
|
|
766
|
+
* 那是「映射表里根本没有这一行」,在库里表示为 NULL 而不是某个状态值。
|
|
767
|
+
*/
|
|
768
|
+
export type FeishuIdentityListStatusFilter = FeishuIdentityResolveStatus | "unmapped";
|
|
769
|
+
export type FeishuIdentityListItem = {
|
|
770
|
+
userId: string;
|
|
771
|
+
email: string;
|
|
772
|
+
name: string;
|
|
773
|
+
userStatus: string;
|
|
774
|
+
provider: string | null;
|
|
775
|
+
appId: string | null;
|
|
776
|
+
/** 未映射为 null;非 admin 读到的是脱敏值(见 `redacted`)。 */
|
|
777
|
+
openId: string | null;
|
|
778
|
+
unionId: string | null;
|
|
779
|
+
/** `null` = 从未同步过,与 `not_found` 不同。 */
|
|
780
|
+
resolveStatus: FeishuIdentityResolveStatus | null;
|
|
781
|
+
lastAttemptedAt: string | null;
|
|
782
|
+
lastResolvedAt: string | null;
|
|
783
|
+
lastErrorCode: string | null;
|
|
784
|
+
};
|
|
785
|
+
export type FeishuIdentityListResponse = {
|
|
786
|
+
items: FeishuIdentityListItem[];
|
|
787
|
+
/** true 表示 `openId`/`unionId` 已脱敏,不可回写。 */
|
|
788
|
+
redacted: boolean;
|
|
789
|
+
summary: {
|
|
790
|
+
total: number;
|
|
791
|
+
resolved: number;
|
|
792
|
+
notFound: number;
|
|
793
|
+
lookupFailed: number;
|
|
794
|
+
unmapped: number;
|
|
795
|
+
};
|
|
796
|
+
};
|
|
797
|
+
/**
|
|
798
|
+
* 写入条目。三个状态的字段集**互斥**(与契约的 discriminated union 同源):
|
|
799
|
+
* 服务端 `.strict()`,多传字段是 400 而不是被忽略。
|
|
800
|
+
*/
|
|
801
|
+
export type FeishuIdentityUpsertEntry = {
|
|
802
|
+
userId: string;
|
|
803
|
+
resolveStatus: "resolved";
|
|
804
|
+
/** `^ou_[A-Za-z0-9]{1,128}$` —— 会被拼进飞书卡片的 `<at id=...>`。 */
|
|
805
|
+
openId: string;
|
|
806
|
+
unionId?: string | null;
|
|
807
|
+
} | {
|
|
808
|
+
userId: string;
|
|
809
|
+
resolveStatus: "not_found";
|
|
810
|
+
} | {
|
|
811
|
+
userId: string;
|
|
812
|
+
resolveStatus: "lookup_failed";
|
|
813
|
+
/** 必填 `^[a-z0-9_.-]{1,64}$`:没有错误码的失败无法排查。 */
|
|
814
|
+
lastErrorCode: string;
|
|
815
|
+
};
|
|
816
|
+
export type FeishuIdentityUpsertResult = {
|
|
817
|
+
userId: string;
|
|
818
|
+
requestedStatus: FeishuIdentityResolveStatus;
|
|
819
|
+
/** 实际落库状态:`lookup_failed` 撞上既有 `resolved` 时这里仍是 `resolved`。 */
|
|
820
|
+
storedStatus: FeishuIdentityResolveStatus;
|
|
821
|
+
mentionable: boolean;
|
|
822
|
+
};
|
|
823
|
+
export type UpsertFeishuIdentitiesResponse = {
|
|
824
|
+
provider: string;
|
|
825
|
+
appId: string;
|
|
826
|
+
results: FeishuIdentityUpsertResult[];
|
|
827
|
+
counts: {
|
|
828
|
+
resolved: number;
|
|
829
|
+
notFound: number;
|
|
830
|
+
lookupFailed: number;
|
|
831
|
+
/** `lookup_failed` 但保住了上次成功解析结果的条数。 */
|
|
832
|
+
preservedResolved: number;
|
|
833
|
+
};
|
|
834
|
+
};
|
|
762
835
|
/**
|
|
763
836
|
* 四眼 registry proposal API 的结构化错误(D2):携带 HTTP status + 稳定 code + staleCode。
|
|
764
837
|
* apply 的 409 + code PROPOSAL_STALE → isStale=true(消费方据此重新提案,保留 staleCode)。
|
|
@@ -794,6 +867,113 @@ export declare class SocialHubHttpError extends Error {
|
|
|
794
867
|
body?: string;
|
|
795
868
|
});
|
|
796
869
|
}
|
|
870
|
+
/**
|
|
871
|
+
* 抓取结果状态。`reauth_required`/`human_required` 属立项 F(授权连接器),
|
|
872
|
+
* 当前 Hub 永不产出,仅预留以免将来扩枚举变成破坏性变更。
|
|
873
|
+
*/
|
|
874
|
+
export type ScrapeOutcome = "content" | "login_wall" | "captcha" | "blocked" | "timeout" | "rate_limited" | "upstream_error" | "empty_content" | "unknown" | "unsupported" | "cancelled" | "reauth_required" | "human_required";
|
|
875
|
+
export type ScrapeFailureStage = "queued" | "dns" | "connect" | "proxy" | "navigate" | "render" | "wait" | "extract" | "parse" | "classify" | "transport" | "unknown";
|
|
876
|
+
export type ScrapeClassificationEvidence = {
|
|
877
|
+
ruleId: string;
|
|
878
|
+
ruleVersion: number;
|
|
879
|
+
strength: "strong" | "weak";
|
|
880
|
+
location: string;
|
|
881
|
+
signal: string;
|
|
882
|
+
excerpt: string | null;
|
|
883
|
+
};
|
|
884
|
+
/** 两层事实:provider 原样事实 + Hub 执行观测。未知一律 null。 */
|
|
885
|
+
export type ScrapeDiagnostics = {
|
|
886
|
+
provider: {
|
|
887
|
+
provider: "firecrawl" | "reddit_direct";
|
|
888
|
+
captureMethod: "firecrawl"
|
|
889
|
+
/** Hub 既有的 Reddit 直连(curl_cffi + TLS 指纹)通道。 */
|
|
890
|
+
| "direct_http" | "official_api" | "authorized_browser";
|
|
891
|
+
providerStatusCode: number | null;
|
|
892
|
+
providerErrorCode: string | null;
|
|
893
|
+
providerErrorType: string | null;
|
|
894
|
+
providerRequestId: string | null;
|
|
895
|
+
providerScrapeId: string | null;
|
|
896
|
+
targetStatusCode: number | null;
|
|
897
|
+
providerFinalUrl: string | null;
|
|
898
|
+
/** `[]` = 确认无重定向;`null` = provider 未提供该事实。 */
|
|
899
|
+
redirectChain: string[] | null;
|
|
900
|
+
};
|
|
901
|
+
execution: {
|
|
902
|
+
attemptCount: number;
|
|
903
|
+
attemptHistory: Array<{
|
|
904
|
+
attempt: number;
|
|
905
|
+
outcome: ScrapeOutcome;
|
|
906
|
+
providerStatusCode: number | null;
|
|
907
|
+
failureStage: ScrapeFailureStage | null;
|
|
908
|
+
durationMs: number;
|
|
909
|
+
waitedMs: number;
|
|
910
|
+
}>;
|
|
911
|
+
failureStage: ScrapeFailureStage | null;
|
|
912
|
+
retryAfterMs: number | null;
|
|
913
|
+
timings: {
|
|
914
|
+
totalMs: number;
|
|
915
|
+
providerMs: number;
|
|
916
|
+
backoffMs: number;
|
|
917
|
+
classifyMs: number;
|
|
918
|
+
};
|
|
919
|
+
errorSummary: string | null;
|
|
920
|
+
};
|
|
921
|
+
};
|
|
922
|
+
type ScrapeResponseCommon = {
|
|
923
|
+
url: string;
|
|
924
|
+
finalUrl: string;
|
|
925
|
+
/** 目标站点状态码(语义未变)。 */
|
|
926
|
+
statusCode: number | null;
|
|
927
|
+
metadata?: Record<string, unknown>;
|
|
928
|
+
requestId: string | null;
|
|
929
|
+
diagnostics: ScrapeDiagnostics;
|
|
930
|
+
classification: {
|
|
931
|
+
outcome: ScrapeOutcome;
|
|
932
|
+
classifierVersion: string;
|
|
933
|
+
classificationEvidence: ScrapeClassificationEvidence[];
|
|
934
|
+
};
|
|
935
|
+
provider: "firecrawl" | "reddit_direct";
|
|
936
|
+
providerRequestId: string | null;
|
|
937
|
+
providerStatusCode: number | null;
|
|
938
|
+
targetStatusCode: number | null;
|
|
939
|
+
attempts: number;
|
|
940
|
+
retryAfterMs: number | null;
|
|
941
|
+
failureStage: ScrapeFailureStage | null;
|
|
942
|
+
classifierVersion: string;
|
|
943
|
+
classificationEvidence: ScrapeClassificationEvidence[];
|
|
944
|
+
warnings: string[];
|
|
945
|
+
};
|
|
946
|
+
/**
|
|
947
|
+
* `ok` 是判别字段。被判定为「确定不是目标正文」的 outcome(login_wall / captcha /
|
|
948
|
+
* blocked / rate_limited / upstream_error / empty_content …)运行时不会带正文字段,
|
|
949
|
+
* 只有 `suppressedContent` 记录被抑制的格式与字符数;`outcome:"unknown"`(证据不足)
|
|
950
|
+
* 仍可能带正文,但 `warnings` 里会标明它未经确认——**不要**当成已验证的正文使用。
|
|
951
|
+
*/
|
|
952
|
+
export type ScrapeUrlResponse = (ScrapeResponseCommon & {
|
|
953
|
+
ok: true;
|
|
954
|
+
outcome: "content";
|
|
955
|
+
markdown?: string;
|
|
956
|
+
html?: string;
|
|
957
|
+
rawHtml?: string;
|
|
958
|
+
links?: string[];
|
|
959
|
+
json?: unknown;
|
|
960
|
+
}) | (ScrapeResponseCommon & {
|
|
961
|
+
ok: false;
|
|
962
|
+
outcome: Exclude<ScrapeOutcome, "content">;
|
|
963
|
+
/**
|
|
964
|
+
* 被抑制的正文格式与字符数(`outcome` 属于「确定不是正文」那一类时出现)。
|
|
965
|
+
* `outcome:"unknown"` 不抑制正文,正文字段仍可能存在——**但它未经确认**。
|
|
966
|
+
*/
|
|
967
|
+
suppressedContent?: Array<{
|
|
968
|
+
format: string;
|
|
969
|
+
chars: number;
|
|
970
|
+
}>;
|
|
971
|
+
markdown?: string;
|
|
972
|
+
html?: string;
|
|
973
|
+
rawHtml?: string;
|
|
974
|
+
links?: string[];
|
|
975
|
+
json?: unknown;
|
|
976
|
+
});
|
|
797
977
|
/**
|
|
798
978
|
* POST /content-review 的 422 稳定错误码:调用方显式声称 `authorRelationHint:"post_author"`,
|
|
799
979
|
* 但 Hub 侧帖子快照证明发布账号不是该帖作者。
|
|
@@ -922,7 +1102,18 @@ export declare class SocialHubClient {
|
|
|
922
1102
|
queued: number;
|
|
923
1103
|
warning?: string;
|
|
924
1104
|
}>;
|
|
925
|
-
|
|
1105
|
+
/**
|
|
1106
|
+
* 更新单条帖子快照。
|
|
1107
|
+
*
|
|
1108
|
+
* ⚠️ 把 `opsStatus` 改成 `deleted` / `banned` 时,**必须**同时带上必选项
|
|
1109
|
+
* `repostRequired`(布尔:是否需补发),否则服务端 400 —— 这是刻意的 fail-closed,
|
|
1110
|
+
* 「需补发」不会默认成 false。「需补发1 / 需补发2」的轮次由服务端按**原帖**的
|
|
1111
|
+
* `repostType` 派生(首发→1、补发一次→2、补发二次→不问也不写),客户端传数字无效。
|
|
1112
|
+
* 原帖 `repostType` 已是 `second` 时不需要带,带了也会被忽略。
|
|
1113
|
+
*/
|
|
1114
|
+
updateRedditPostSnapshot(teamId: string, snapshotId: string, body: Record<string, unknown> & {
|
|
1115
|
+
repostRequired?: boolean;
|
|
1116
|
+
}): Promise<{
|
|
926
1117
|
ok: boolean;
|
|
927
1118
|
}>;
|
|
928
1119
|
deleteRedditPostSnapshot(teamId: string, snapshotId: string): Promise<{
|
|
@@ -2336,6 +2527,37 @@ export declare class SocialHubClient {
|
|
|
2336
2527
|
listSystemUsers(): Promise<{
|
|
2337
2528
|
items: unknown[];
|
|
2338
2529
|
}>;
|
|
2530
|
+
/**
|
|
2531
|
+
* `GET /v1/system/feishu-identities` —— Hub 用户 ↔ 飞书 open_id 的映射现状。
|
|
2532
|
+
*
|
|
2533
|
+
* 返回**全体用户**(users LEFT JOIN 映射表),所以 `resolveStatus === null` 表示
|
|
2534
|
+
* 「从未同步过」,与 `not_found`(查过、通讯录里没这人)是两回事。
|
|
2535
|
+
*
|
|
2536
|
+
* ⚠️ 非「不受限交互式 admin 登录」读到的 `openId`/`unionId` 是脱敏的 `ou_***`。
|
|
2537
|
+
* 判据是响应里的 `redacted`,不要拿 `openId` 的字符串形态去猜 —— 脱敏值也以
|
|
2538
|
+
* `ou_` 开头,直接透传会写出一个永远 @ 不到人的映射。
|
|
2539
|
+
*/
|
|
2540
|
+
listFeishuIdentities(params?: {
|
|
2541
|
+
provider?: string;
|
|
2542
|
+
appId?: string;
|
|
2543
|
+
status?: FeishuIdentityListStatusFilter;
|
|
2544
|
+
includeInactiveUsers?: boolean;
|
|
2545
|
+
}): Promise<FeishuIdentityListResponse>;
|
|
2546
|
+
/**
|
|
2547
|
+
* `PUT /v1/system/feishu-identities` —— 批量落库(幂等,同一批重放结果相同)。
|
|
2548
|
+
*
|
|
2549
|
+
* 写入面只认不受限的交互式 admin 登录:**API key 一律 403**,所以这个方法在
|
|
2550
|
+
* 服务端到服务端的集成里不可用,它是给交互式运维工具(CLI/后台)用的。
|
|
2551
|
+
*
|
|
2552
|
+
* 语义上最贵的一条:`not_found` 会清空既有 `openId`(离职语义)。查询失败必须用
|
|
2553
|
+
* `lookup_failed`(服务端会保住上次成功解析的值),把「没问出来」写成 `not_found`
|
|
2554
|
+
* 等于静默注销一个本来能收到告警的人。
|
|
2555
|
+
*/
|
|
2556
|
+
upsertFeishuIdentities(body: {
|
|
2557
|
+
provider?: "feishu";
|
|
2558
|
+
appId: string;
|
|
2559
|
+
entries: FeishuIdentityUpsertEntry[];
|
|
2560
|
+
}): Promise<UpsertFeishuIdentitiesResponse>;
|
|
2339
2561
|
createSystemUser(body: {
|
|
2340
2562
|
email: string;
|
|
2341
2563
|
name: string;
|
|
@@ -2549,28 +2771,33 @@ export declare class SocialHubClient {
|
|
|
2549
2771
|
* 通用网页抓取。Reddit .json(mode "reddit-json" 或 .json URL)走 API 内直连
|
|
2550
2772
|
* curl_cffi+住宅代理返回结构化 JSON;HTML/普通网页经自托管 Firecrawl 返回
|
|
2551
2773
|
* markdown/html/rawHtml/links。
|
|
2774
|
+
*
|
|
2775
|
+
* **务必先看 `ok`/`outcome`,不要只看 HTTP 状态**(立项 A):Firecrawl 返回 200
|
|
2776
|
+
* 但正文是登录页/验证码页时,Hub 会回 HTTP 200 + `ok:false` + `outcome`
|
|
2777
|
+
* (`login_wall`/`captcha`/`empty_content` 等)并**不回传正文字段**,同时给出
|
|
2778
|
+
* `classificationEvidence` 说明凭什么这么判。`outcome:"unknown"`(证据不足)仍会
|
|
2779
|
+
* 带正文,但它**未经确认**,`warnings` 里有显式提示——不要当成已验证正文使用。
|
|
2780
|
+
*
|
|
2781
|
+
* 技术层失败(provider 非 2xx / Hub 等待超时 / 网络错误)抛 `SocialHubHttpError`
|
|
2782
|
+
* (429/502/504),`code` 为 `SCRAPE_RATE_LIMITED`/`SCRAPE_TIMEOUT`/
|
|
2783
|
+
* `SCRAPE_UPSTREAM_ERROR`,`details` 里带 provider typed code/error/request id、
|
|
2784
|
+
* 失败阶段与尝试次数。
|
|
2552
2785
|
*/
|
|
2553
2786
|
scrapeUrl(body: {
|
|
2554
2787
|
url: string;
|
|
2555
2788
|
formats?: Array<"markdown" | "html" | "rawHtml" | "links">;
|
|
2556
2789
|
mode?: "raw" | "reddit-json";
|
|
2557
2790
|
timeoutMs?: number;
|
|
2558
|
-
}): Promise<
|
|
2559
|
-
url: string;
|
|
2560
|
-
finalUrl: string;
|
|
2561
|
-
statusCode: number | null;
|
|
2562
|
-
markdown?: string;
|
|
2563
|
-
html?: string;
|
|
2564
|
-
rawHtml?: string;
|
|
2565
|
-
links?: string[];
|
|
2566
|
-
json?: unknown;
|
|
2567
|
-
metadata?: Record<string, unknown>;
|
|
2568
|
-
}>;
|
|
2791
|
+
}): Promise<ScrapeUrlResponse>;
|
|
2569
2792
|
getScrapeStatus(): Promise<{
|
|
2570
2793
|
configured: boolean;
|
|
2571
2794
|
firecrawl?: boolean;
|
|
2572
2795
|
redditDirect?: boolean;
|
|
2573
2796
|
inFlight: number;
|
|
2797
|
+
/** 立项 A 新增:当前 2xx 页面分类器版本。 */
|
|
2798
|
+
classifierVersion?: string;
|
|
2799
|
+
/** 立项 A 新增:生效的尝试次数上限(含首次)。 */
|
|
2800
|
+
maxAttempts?: number;
|
|
2574
2801
|
}>;
|
|
2575
2802
|
/** GET subjects/:hotPostId — active spec 下该 hot_post 的 current proposed 分类(proposed|missing)。 */
|
|
2576
2803
|
getContentClassificationSubject(hotPostId: string, params?: {
|
|
@@ -3370,4 +3597,5 @@ export type NotificationPullResponseDto = {
|
|
|
3370
3597
|
* 与 contracts `compareNotificationSeq` 同口径;SDK 侧复刻是因为不能引 contracts。
|
|
3371
3598
|
*/
|
|
3372
3599
|
export declare function compareNotificationSeqStrings(left: string, right: string): number;
|
|
3600
|
+
export {};
|
|
3373
3601
|
//# sourceMappingURL=index.d.ts.map
|