@chainlesschain/personal-data-hub 0.4.18 → 0.4.23

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.
@@ -0,0 +1,360 @@
1
+ /**
2
+ * §A13 — 懂车帝 (Dongchedi, com.ss.android.auto) adapter, dual-mode (snapshot +
3
+ * cookie-api). Phase 13+ §12.1 line-784 ROI ⭐⭐ "汽车关注".
4
+ *
5
+ * 懂车帝 (ByteDance auto vertical) personal data = the user's car-interest
6
+ * footprint: car series / creators they follow, and articles / videos / series
7
+ * they favourited. Both are interest signals → favourite maps to a LIKE event,
8
+ * follow to a contact Person (the followed series/creator). Mirrors the
9
+ * social-zhihu two-mode shape.
10
+ *
11
+ * 1. snapshot mode (opts.inputPath): JSON schemaVersion 1, stateless.
12
+ * 2. cookie-api mode (opts.account.cookies): fetch the user's favourites +
13
+ * follows from dongchedi.com via the injected `fetchFn`, paginate; a sign
14
+ * seam (opts.signProvider) covers ByteDance's signed-request token (X-Bogus
15
+ * / msToken family); best-effort unsigned when absent. Endpoints overridable
16
+ * via opts.favouritesUrl / opts.followsUrl (best-effort, not field-verified
17
+ * — FAMILY-23 playbook). account OPTIONAL — the cookie carries identity.
18
+ *
19
+ * Snapshot schema (schemaVersion 1):
20
+ * {
21
+ * "schemaVersion": 1, "snapshottedAt": <ms>,
22
+ * "account": { "userId": "...", "name": "..." },
23
+ * "events": [
24
+ * { "kind": "favourite", "id": "fav-<id>", "itemId": "...", "title": "...",
25
+ * "contentType": "article|video|series", "url": "...", "capturedAt": <ms> },
26
+ * { "kind": "follow", "id": "follow-<id>", "followId": "...", "name": "...",
27
+ * "followType": "series|creator", "url": "...", "capturedAt": <ms> }
28
+ * ]
29
+ * }
30
+ */
31
+
32
+ "use strict";
33
+
34
+ const fs = require("node:fs");
35
+ const { newId } = require("../../ids");
36
+ const {
37
+ ENTITY_TYPES,
38
+ PERSON_SUBTYPES,
39
+ EVENT_SUBTYPES,
40
+ CAPTURED_BY,
41
+ } = require("../../constants");
42
+ const { CookieAuth } = require("../shopping-base");
43
+
44
+ const NAME = "social-dongchedi";
45
+ const VERSION = "0.1.0";
46
+ const SNAPSHOT_SCHEMA_VERSION = 1;
47
+
48
+ const KIND_FAVOURITE = "favourite";
49
+ const KIND_FOLLOW = "follow";
50
+ const VALID_SNAPSHOT_KINDS = Object.freeze([KIND_FAVOURITE, KIND_FOLLOW]);
51
+
52
+ // Best-effort dongchedi.com endpoints. Overridable via opts.*Url.
53
+ const FAVOURITES_URL = "https://www.dongchedi.com/motor/profile/get_favorite_list";
54
+ const FOLLOWS_URL = "https://www.dongchedi.com/motor/profile/get_follow_list";
55
+ const PAGE_SIZE = 20;
56
+
57
+ function parseTime(v) {
58
+ if (Number.isFinite(v)) return v > 1e12 ? v : v >= 1e9 ? v * 1000 : v;
59
+ if (typeof v === "string") {
60
+ if (/^\d+$/.test(v)) {
61
+ const n = parseInt(v, 10);
62
+ return n > 1e12 ? n : n >= 1e9 ? n * 1000 : n;
63
+ }
64
+ const t = Date.parse(v);
65
+ return Number.isFinite(t) ? t : null;
66
+ }
67
+ return null;
68
+ }
69
+
70
+ function stableOriginalId(kind, id) {
71
+ const safe =
72
+ (typeof id === "string" && id.length > 0 && id) ||
73
+ (typeof id === "number" && Number.isFinite(id) && String(id)) ||
74
+ `unknown-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
75
+ return `dongchedi:${kind}:${safe}`;
76
+ }
77
+
78
+ class DongchediAdapter {
79
+ constructor(opts = {}) {
80
+ this.account = opts.account || null;
81
+ this._cookieAuth =
82
+ opts.account && opts.account.cookies
83
+ ? new CookieAuth({ platform: "dongchedi", cookies: opts.account.cookies })
84
+ : null;
85
+ this._fetchFn = typeof opts.fetchFn === "function" ? opts.fetchFn : defaultFetch;
86
+ this._signProvider =
87
+ typeof opts.signProvider === "function" ? opts.signProvider : null;
88
+ this._urls = {
89
+ favourites: opts.favouritesUrl || FAVOURITES_URL,
90
+ follows: opts.followsUrl || FOLLOWS_URL,
91
+ };
92
+
93
+ this.name = NAME;
94
+ this.version = VERSION;
95
+ this.capabilities = [
96
+ "sync:snapshot",
97
+ "sync:cookie-api",
98
+ "parse:dongchedi-favourite",
99
+ "parse:dongchedi-follow",
100
+ ];
101
+ this.extractMode = "web-api";
102
+ this.rateLimits = { perMinute: 8, perDay: 200 };
103
+ this.dataDisclosure = {
104
+ fields: [
105
+ "dongchedi:favourite (title / contentType / url)",
106
+ "dongchedi:follow (name / followType)",
107
+ ],
108
+ sensitivity: "low",
109
+ legalGate: false,
110
+ defaultInclude: { favourite: true, follow: true },
111
+ };
112
+
113
+ this._deps = { fs };
114
+ }
115
+
116
+ async authenticate(ctx = {}) {
117
+ if (ctx && typeof ctx.inputPath === "string" && ctx.inputPath.length > 0) {
118
+ try {
119
+ this._deps.fs.accessSync(ctx.inputPath, this._deps.fs.constants.R_OK);
120
+ } catch (err) {
121
+ return {
122
+ ok: false,
123
+ reason: "INPUT_PATH_UNREADABLE",
124
+ message: `snapshot not readable at ${ctx.inputPath}: ${err.message}`,
125
+ };
126
+ }
127
+ return { ok: true, mode: "snapshot-file" };
128
+ }
129
+ if (this._cookieAuth) {
130
+ const ok = await this._cookieAuth.validate();
131
+ if (!ok) return { ok: false, reason: "INVALID_COOKIE", error: "cookies missing" };
132
+ return { ok: true, account: (this.account && this.account.userId) || null, mode: "cookie" };
133
+ }
134
+ return {
135
+ ok: false,
136
+ reason: "NO_INPUT",
137
+ message:
138
+ "social-dongchedi.authenticate: needs opts.inputPath (snapshot mode) OR opts.account.cookies (cookie-api mode)",
139
+ };
140
+ }
141
+
142
+ async healthCheck() {
143
+ if (this._cookieAuth) {
144
+ const r = await this.authenticate();
145
+ return r.ok ? { ok: true, lastChecked: Date.now() } : { ok: false, reason: r.reason, error: r.error };
146
+ }
147
+ return { ok: true, lastChecked: Date.now() };
148
+ }
149
+
150
+ async *sync(opts = {}) {
151
+ if (typeof opts.inputPath === "string" && opts.inputPath.length > 0) {
152
+ yield* this._syncViaSnapshot(opts);
153
+ return;
154
+ }
155
+ if (this._cookieAuth) {
156
+ yield* this._syncViaCookie(opts);
157
+ return;
158
+ }
159
+ throw new Error(
160
+ "social-dongchedi.sync: needs opts.inputPath (snapshot mode) OR opts.account.cookies (cookie-api mode)",
161
+ );
162
+ }
163
+
164
+ async *_syncViaSnapshot(opts) {
165
+ const raw = this._deps.fs.readFileSync(opts.inputPath, "utf-8");
166
+ const snapshot = JSON.parse(raw);
167
+ if (!snapshot || typeof snapshot !== "object" || snapshot.schemaVersion !== SNAPSHOT_SCHEMA_VERSION) {
168
+ throw new Error(
169
+ `social-dongchedi.sync: snapshot schemaVersion mismatch (got ${snapshot && snapshot.schemaVersion}, expected ${SNAPSHOT_SCHEMA_VERSION})`,
170
+ );
171
+ }
172
+ const fallback =
173
+ Number.isFinite(snapshot.snapshottedAt) && snapshot.snapshottedAt > 0
174
+ ? Math.floor(snapshot.snapshottedAt)
175
+ : Date.now();
176
+ const account = snapshot.account && typeof snapshot.account === "object" ? snapshot.account : null;
177
+ const include = opts.include || {};
178
+ const limit = Number.isInteger(opts.limit) && opts.limit > 0 ? opts.limit : Infinity;
179
+ const events = Array.isArray(snapshot.events) ? snapshot.events : [];
180
+ let emitted = 0;
181
+ for (const ev of events) {
182
+ if (emitted >= limit) return;
183
+ if (!ev || typeof ev !== "object" || !VALID_SNAPSHOT_KINDS.includes(ev.kind)) continue;
184
+ if (include[ev.kind] === false) continue;
185
+ const id = (typeof ev.id === "string" && ev.id) || ev.itemId || ev.followId || null;
186
+ yield {
187
+ adapter: NAME,
188
+ kind: ev.kind,
189
+ originalId: stableOriginalId(ev.kind, id),
190
+ capturedAt: parseTime(ev.capturedAt) || fallback,
191
+ payload: { ...ev, account },
192
+ };
193
+ emitted += 1;
194
+ }
195
+ }
196
+
197
+ async *_syncViaCookie(opts = {}) {
198
+ if (!(await this._cookieAuth.validate())) return;
199
+ const cookies = this._cookieAuth.toHeader();
200
+ const include = opts.include || {};
201
+ const limit = Number.isInteger(opts.limit) && opts.limit > 0 ? opts.limit : Infinity;
202
+ const maxPages = Number.isInteger(opts.maxPages) && opts.maxPages > 0 ? opts.maxPages : 10;
203
+
204
+ const plan = [
205
+ { kind: KIND_FAVOURITE, url: this._urls.favourites },
206
+ { kind: KIND_FOLLOW, url: this._urls.follows },
207
+ ];
208
+
209
+ let emitted = 0;
210
+ for (const step of plan) {
211
+ if (include[step.kind] === false) continue;
212
+ let offset = 0;
213
+ let page = 0;
214
+ while (page < maxPages) {
215
+ const query = { offset, count: PAGE_SIZE };
216
+ let sign = null;
217
+ if (this._signProvider) {
218
+ sign = await this._signProvider({ url: step.url, query, cookies });
219
+ }
220
+ const resp = await this._fetchFn({ url: step.url, cookies, query, sign });
221
+ const items = extractData(resp);
222
+ if (!items.length) break;
223
+ for (const it of items) {
224
+ if (!it || typeof it !== "object") continue;
225
+ if (emitted >= limit) return;
226
+ const id = step.kind === KIND_FOLLOW
227
+ ? it.follow_id || it.user_id || it.series_id || it.id
228
+ : it.group_id || it.item_id || it.id;
229
+ yield {
230
+ adapter: NAME,
231
+ kind: step.kind,
232
+ originalId: stableOriginalId(step.kind, id),
233
+ capturedAt: parseTime(it.create_time || it.favorite_time || it.follow_time) || Date.now(),
234
+ payload: { item: it, kind: step.kind, cookie: true },
235
+ };
236
+ emitted += 1;
237
+ }
238
+ if (isEnd(resp) || items.length < PAGE_SIZE) break;
239
+ offset += items.length;
240
+ page += 1;
241
+ }
242
+ }
243
+ }
244
+
245
+ normalize(raw) {
246
+ if (!raw || !raw.payload) throw new Error("DongchediAdapter.normalize: payload missing");
247
+ const ingestedAt = Date.now();
248
+ const kind = raw.kind || raw.payload.kind;
249
+ if (kind === KIND_FAVOURITE) return normalizeFavourite(raw, ingestedAt);
250
+ if (kind === KIND_FOLLOW) return normalizeFollow(raw, ingestedAt);
251
+ throw new Error(`DongchediAdapter.normalize: unknown kind ${kind}`);
252
+ }
253
+ }
254
+
255
+ // ─── cookie response helpers ─────────────────────────────────────────────────
256
+
257
+ function extractData(resp) {
258
+ if (!resp || typeof resp !== "object") return [];
259
+ if (Array.isArray(resp.data)) return resp.data;
260
+ if (Array.isArray(resp.list)) return resp.list;
261
+ const d = resp.data;
262
+ if (d && typeof d === "object") {
263
+ if (Array.isArray(d.list)) return d.list;
264
+ if (Array.isArray(d.favorite_list)) return d.favorite_list;
265
+ if (Array.isArray(d.follow_list)) return d.follow_list;
266
+ if (Array.isArray(d.records)) return d.records;
267
+ }
268
+ return [];
269
+ }
270
+
271
+ function isEnd(resp) {
272
+ const d = resp && resp.data && typeof resp.data === "object" ? resp.data : resp;
273
+ if (d && typeof d === "object" && (d.has_more === false || d.has_more === 0)) return true;
274
+ return false;
275
+ }
276
+
277
+ // ─── per-kind normalizers (snapshot fields OR cookie payload.item) ────────────
278
+
279
+ function buildSource(raw, occurredAt) {
280
+ return {
281
+ adapter: NAME,
282
+ adapterVersion: VERSION,
283
+ originalId: raw.originalId,
284
+ capturedAt: raw.capturedAt || occurredAt,
285
+ capturedBy: CAPTURED_BY.API,
286
+ };
287
+ }
288
+
289
+ function normalizeFavourite(raw, ingestedAt) {
290
+ const p = raw.payload;
291
+ const it = p.cookie ? p.item : p;
292
+ const title = it.title || it.group_title || it.name || "";
293
+ const occurredAt = parseTime(it.capturedAt || it.create_time || it.favorite_time || raw.capturedAt) || ingestedAt;
294
+ const source = buildSource(raw, occurredAt);
295
+ return {
296
+ events: [
297
+ {
298
+ id: newId(),
299
+ type: ENTITY_TYPES.EVENT,
300
+ subtype: EVENT_SUBTYPES.LIKE,
301
+ occurredAt,
302
+ actor: "person-self",
303
+ content: { title: `收藏: ${title}`.trim(), text: title },
304
+ ingestedAt,
305
+ source,
306
+ extra: {
307
+ platform: "dongchedi",
308
+ itemId: (it.itemId || it.group_id || it.item_id || it.id) != null
309
+ ? String(it.itemId || it.group_id || it.item_id || it.id) : null,
310
+ contentType: it.contentType || it.content_type || it.type || null,
311
+ url: it.url || it.share_url || null,
312
+ },
313
+ },
314
+ ],
315
+ persons: [],
316
+ places: [],
317
+ items: [],
318
+ topics: [],
319
+ };
320
+ }
321
+
322
+ function normalizeFollow(raw, ingestedAt) {
323
+ const p = raw.payload;
324
+ const it = p.cookie ? p.item : p;
325
+ const followId = it.followId || it.follow_id || it.user_id || it.series_id || it.id || `unknown-${newId()}`;
326
+ const name = it.name || it.series_name || it.user_name || it.screen_name || "(unnamed)";
327
+ const followType = it.followType || it.follow_type || (it.series_id ? "series" : "creator");
328
+ const occurredAt = parseTime(it.capturedAt || it.follow_time || raw.capturedAt) || ingestedAt;
329
+ const source = buildSource(raw, occurredAt);
330
+ const person = {
331
+ id: `person-dongchedi-${followId}`,
332
+ type: ENTITY_TYPES.PERSON,
333
+ subtype: PERSON_SUBTYPES.CONTACT,
334
+ names: [name],
335
+ ingestedAt,
336
+ source,
337
+ identifiers: { "dongchedi-id": [String(followId)] },
338
+ extra: {
339
+ platform: "dongchedi",
340
+ followType,
341
+ url: it.url || it.share_url || null,
342
+ followedAt: occurredAt,
343
+ },
344
+ };
345
+ return { events: [], persons: [person], places: [], items: [], topics: [] };
346
+ }
347
+
348
+ async function defaultFetch(_opts) {
349
+ throw new Error("social-dongchedi: no fetchFn configured for cookie-api mode");
350
+ }
351
+
352
+ module.exports = {
353
+ DongchediAdapter,
354
+ extractData,
355
+ isEnd,
356
+ NAME,
357
+ VERSION,
358
+ SNAPSHOT_SCHEMA_VERSION,
359
+ VALID_SNAPSHOT_KINDS,
360
+ };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * §13+ — 西瓜视频 (Xigua / Ixigua, com.ss.android.article.video) adapter.
3
+ * §12.1 Phase 13+ ROI ⭐⭐ "观看历史". Thin wrapper over _video-base.
4
+ *
5
+ * 西瓜视频 (ByteDance) exposes the user's watch history + favourites via
6
+ * ixigua.com APIs; this adapter supplies the endpoints + field mapping, the base
7
+ * handles snapshot + cookie-api orchestration + normalize (MEDIA / LIKE event +
8
+ * MEDIA item). Endpoints best-effort + overridable (some need a ByteDance signed
9
+ * token via opts.signProvider — not field-verified, FAMILY-23 playbook).
10
+ */
11
+
12
+ "use strict";
13
+
14
+ const { createVideoAdapter, parseTime, SNAPSHOT_SCHEMA_VERSION } = require("../_video-base");
15
+
16
+ const NAME = "video-xigua";
17
+ const VERSION = "0.1.0";
18
+
19
+ const WATCH_URL = "https://api.ixigua.com/api/history/list";
20
+ const FAVOURITE_URL = "https://api.ixigua.com/api/favorite/list";
21
+
22
+ function extractItems(resp) {
23
+ if (!resp || typeof resp !== "object") return [];
24
+ if (Array.isArray(resp.data)) return resp.data;
25
+ if (Array.isArray(resp.list)) return resp.list;
26
+ const d = resp.data;
27
+ if (d && typeof d === "object") {
28
+ if (Array.isArray(d.list)) return d.list;
29
+ if (Array.isArray(d.records)) return d.records;
30
+ if (Array.isArray(d.history)) return d.history;
31
+ if (Array.isArray(d.favorites)) return d.favorites;
32
+ }
33
+ return [];
34
+ }
35
+
36
+ function mapItem(it) {
37
+ if (!it || typeof it !== "object") return null;
38
+ // ByteDance items nest the video under article/item_info on some endpoints.
39
+ const v = it.article || it.item_info || it.video || it;
40
+ const videoId = v.group_id || v.groupId || v.item_id || v.gid || v.vid || v.id || it.group_id || it.id;
41
+ if (!videoId) return null;
42
+ return {
43
+ videoId: String(videoId),
44
+ title: v.title || v.video_title || v.name || it.title || "(未知视频)",
45
+ category: v.category || v.category_name || v.channel || null,
46
+ episode: null,
47
+ channel: v.user_name || v.author_name || v.source || null,
48
+ durationSec: Number.isFinite(v.video_duration)
49
+ ? v.video_duration
50
+ : Number.isFinite(v.duration)
51
+ ? v.duration
52
+ : null,
53
+ url: v.share_url || v.url || (videoId ? `https://www.ixigua.com/${videoId}` : null),
54
+ occurredAt: parseTime(it.behot_time || it.action_time || it.create_time || v.behot_time || v.publish_time),
55
+ };
56
+ }
57
+
58
+ const XiguaVideoAdapter = createVideoAdapter({
59
+ NAME,
60
+ VERSION,
61
+ platform: "xigua",
62
+ watchUrl: WATCH_URL,
63
+ favouriteUrl: FAVOURITE_URL,
64
+ extractItems,
65
+ mapItem,
66
+ });
67
+
68
+ module.exports = { XiguaVideoAdapter, extractItems, mapItem, NAME, VERSION, SNAPSHOT_SCHEMA_VERSION };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * 企业微信 (WeChat Work / WeCom) 电脑版 — honest best-effort local IM DB reader
5
+ * (qq-pc / dingtalk-pc / feishu-pc 模式).
6
+ *
7
+ * ⚠️ v0.1: 企业微信桌面本地库(C:\\Users\\<user>\\Documents\\WXWork\\...)为私有
8
+ * 结构、通常加密(同微信 SQLCipher 系)、随版本变化。本 adapter 做到可靠开库 +
9
+ * 发现消息表 + 防御探测列 + 保留原始行 + 响亮诊断;文本解析尽力而为,真机上按需
10
+ * 扩展 colCandidates。建议先把库解密为明文(或采集时附带 --key)再指向它。
11
+ */
12
+
13
+ const { createLocalImPcAdapter } = require("../_local-im-pc-adapter");
14
+
15
+ const WeWorkPcAdapter = createLocalImPcAdapter({
16
+ name: "wework-pc",
17
+ platform: "wework",
18
+ version: "0.1.0",
19
+ tablePattern: /msg|message|chat|conversation|im_|session/i,
20
+ colCandidates: {
21
+ // 企业微信常见列猜测(真机微调)
22
+ time: ["createTime", "create_time", "msgCreateTime", "sendTime", "send_time", "timestamp"],
23
+ sender: ["sender", "senderId", "fromUser", "from", "talker", "vid"],
24
+ peer: ["conversationId", "roomId", "chatId", "talker", "toUser", "conversation"],
25
+ content: ["content", "text", "msgContent", "message", "digest", "summary"],
26
+ },
27
+ needHint:
28
+ "wework-pc: 需提供企业微信桌面本地库路径(WXWork 目录下,私有/通常加密,建议先解密为明文或提供 key)",
29
+ });
30
+
31
+ module.exports = { WeWorkPcAdapter, NAME: "wework-pc", VERSION: "0.1.0" };
package/lib/index.js CHANGED
@@ -55,6 +55,8 @@ const { WeiboAdapter } = require("./adapters/social-weibo");
55
55
  const { ZhihuAdapter } = require("./adapters/social-zhihu");
56
56
  const { BossZhipinAdapter } = require("./adapters/recruit-boss");
57
57
  const { CsdnAdapter } = require("./adapters/social-csdn");
58
+ const { DongchediAdapter } = require("./adapters/social-dongchedi");
59
+ const { TianyanchaAdapter } = require("./adapters/biz-tianyancha");
58
60
  const { DouyinAdapter } = require("./adapters/social-douyin");
59
61
  const { XiaohongshuAdapter } = require("./adapters/social-xiaohongshu");
60
62
  const { ToutiaoAdapter } = require("./adapters/social-toutiao");
@@ -73,12 +75,18 @@ const { NeteaseMusicAdapter } = require("./adapters/netease-music");
73
75
  const { KugouMusicAdapter } = require("./adapters/music-kugou");
74
76
  const { IqiyiVideoAdapter } = require("./adapters/video-iqiyi");
75
77
  const { TencentVideoAdapter } = require("./adapters/video-tencent");
78
+ const { XiguaVideoAdapter } = require("./adapters/video-xigua");
76
79
  const { WeReadAdapter } = require("./adapters/weread");
77
80
  const { WpsDocAdapter } = require("./adapters/doc-wps");
78
81
  const { TencentDocsAdapter } = require("./adapters/doc-tencent-docs");
79
82
  const { BaiduNetdiskAdapter } = require("./adapters/doc-baidu-netdisk");
83
+ const { CamScannerDocAdapter } = require("./adapters/doc-camscanner");
84
+ const { IXiamenAdapter } = require("./adapters/gov-ixiamen");
85
+ const { MeiyouAdapter } = require("./adapters/health-meiyou");
86
+ const { TaxAdapter } = require("./adapters/gov-tax");
80
87
  const { DingTalkPcAdapter } = require("./adapters/dingtalk-pc");
81
88
  const { FeishuPcAdapter } = require("./adapters/feishu-pc");
89
+ const { WeWorkPcAdapter } = require("./adapters/wework-pc");
82
90
  const { TelegramAdapter } = require("./adapters/messaging-telegram");
83
91
  const { WhatsAppAdapter } = require("./adapters/messaging-whatsapp");
84
92
  const entityResolver = require("./entity-resolver");
@@ -297,6 +305,8 @@ module.exports = {
297
305
  ZhihuAdapter,
298
306
  BossZhipinAdapter,
299
307
  CsdnAdapter,
308
+ DongchediAdapter,
309
+ TianyanchaAdapter,
300
310
  DouyinAdapter,
301
311
  XiaohongshuAdapter,
302
312
  ToutiaoAdapter,
@@ -314,12 +324,18 @@ module.exports = {
314
324
  KugouMusicAdapter,
315
325
  IqiyiVideoAdapter,
316
326
  TencentVideoAdapter,
327
+ XiguaVideoAdapter,
317
328
  WeReadAdapter,
318
329
  WpsDocAdapter,
319
330
  TencentDocsAdapter,
320
331
  BaiduNetdiskAdapter,
332
+ CamScannerDocAdapter,
333
+ IXiamenAdapter,
334
+ MeiyouAdapter,
335
+ TaxAdapter,
321
336
  DingTalkPcAdapter,
322
337
  FeishuPcAdapter,
338
+ WeWorkPcAdapter,
323
339
  TelegramAdapter,
324
340
  WhatsAppAdapter,
325
341
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chainlesschain/personal-data-hub",
3
- "version": "0.4.18",
3
+ "version": "0.4.23",
4
4
  "description": "Personal Data Hub — UnifiedSchema + validators + KG ingest helpers for the data-back-to-the-individual middleware",
5
5
  "type": "commonjs",
6
6
  "main": "lib/index.js",