@chainlesschain/personal-data-hub 0.2.1 → 0.2.3
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/__tests__/adapters/social-toutiao-kuaishou-scaffold.test.js +58 -16
- package/__tests__/adapters/wechat-frida-agent.test.js +132 -1
- package/__tests__/integration/social-bilibili-pipeline.test.js +261 -0
- package/__tests__/longtail-adapters.test.js +60 -14
- package/__tests__/messaging-qq-snapshot.test.js +294 -0
- package/__tests__/shopping-pinduoduo-snapshot.test.js +302 -0
- package/__tests__/shopping-snapshot.test.js +438 -0
- package/__tests__/social-adapters.test.js +91 -17
- package/__tests__/social-bilibili-snapshot.test.js +278 -0
- package/__tests__/social-douyin-snapshot.test.js +253 -0
- package/__tests__/social-kuaishou-snapshot.test.js +309 -0
- package/__tests__/social-toutiao-snapshot.test.js +314 -0
- package/__tests__/social-weibo-snapshot.test.js +234 -0
- package/__tests__/social-xiaohongshu-snapshot.test.js +232 -0
- package/__tests__/travel-maps-snapshot.test.js +426 -0
- package/__tests__/vault-driver-error.test.js +74 -0
- package/__tests__/wechat-adapter.test.js +118 -0
- package/lib/adapters/messaging-qq/index.js +498 -92
- package/lib/adapters/shopping-jd/index.js +228 -25
- package/lib/adapters/shopping-meituan/index.js +222 -26
- package/lib/adapters/shopping-pinduoduo/index.js +275 -0
- package/lib/adapters/social-bilibili/adapter.js +500 -0
- package/lib/adapters/social-bilibili/index.js +21 -169
- package/lib/adapters/social-douyin/index.js +454 -63
- package/lib/adapters/social-kuaishou/index.js +379 -127
- package/lib/adapters/social-toutiao/index.js +400 -130
- package/lib/adapters/social-weibo/index.js +393 -95
- package/lib/adapters/social-xiaohongshu/index.js +389 -49
- package/lib/adapters/travel-baidu-map/index.js +286 -26
- package/lib/adapters/travel-tencent-map/index.js +414 -0
- package/lib/adapters/wechat/content-parser.js +11 -2
- package/lib/adapters/wechat/db-reader.js +88 -10
- package/lib/adapters/wechat/frida-agent/loader.js +7 -0
- package/lib/adapters/wechat/frida-agent/wechat-key-hook.js +140 -18
- package/lib/adapters/wechat/key-providers/frida-key-provider.js +8 -0
- package/lib/adapters/wechat/normalize.js +12 -3
- package/lib/index.js +5 -1
- package/lib/vault.js +60 -8
- package/package.json +2 -1
|
@@ -32,7 +32,10 @@
|
|
|
32
32
|
"use strict";
|
|
33
33
|
|
|
34
34
|
(function () {
|
|
35
|
-
|
|
35
|
+
// sjqz-verified module name is `libWCDB.so` (uppercase); some WeChat
|
|
36
|
+
// builds ship lowercase. Try both — first match wins, no extra cost
|
|
37
|
+
// because Process.findModuleByName is a cheap lookup.
|
|
38
|
+
var TARGET_MODULES = ["libWCDB.so", "libwcdb.so"];
|
|
36
39
|
// Primary symbol per §18.3. Add fallbacks below — version drift will
|
|
37
40
|
// shift the export name; host treats first hit as authoritative.
|
|
38
41
|
var SYMBOLS = [
|
|
@@ -60,63 +63,182 @@
|
|
|
60
63
|
// the host detaches quickly (anti-detection §18.6 #4).
|
|
61
64
|
var fired = false;
|
|
62
65
|
|
|
66
|
+
// Sig-aware arg index map. The host treats the first 'key' event as
|
|
67
|
+
// authoritative, so picking the wrong index for v2 = host gets the
|
|
68
|
+
// database NAME pointer (e.g. "main") and DB opens fail silently.
|
|
69
|
+
// sqlite3_key(sqlite3 *db, const void *pKey, int nKey)
|
|
70
|
+
// args[0]=db, args[1]=key, args[2]=len
|
|
71
|
+
// sqlite3_key_v2(sqlite3 *db, const char *zDbName, const void *pKey, int nKey)
|
|
72
|
+
// args[0]=db, args[1]=name, args[2]=key, args[3]=len
|
|
73
|
+
// wcdb_setkey / WCDBKeyDerive: unknown sig — assume sqlite3_key shape
|
|
74
|
+
// Mangled C++: WCDB::Database::setCipherKey(*this, const std::string&)
|
|
75
|
+
// args[0]=this, args[1]=&string (length needs .size()) — not handled
|
|
76
|
+
// here; emit error so the host falls back to MD5 path.
|
|
77
|
+
function argIndicesFor(symbolName) {
|
|
78
|
+
if (symbolName === "sqlite3_key_v2") {
|
|
79
|
+
return { key: 2, len: 3, sig: "v2" };
|
|
80
|
+
}
|
|
81
|
+
if (symbolName.indexOf("_ZN4WCDB") === 0) {
|
|
82
|
+
return { key: -1, len: -1, sig: "mangled-cpp" };
|
|
83
|
+
}
|
|
84
|
+
return { key: 1, len: 2, sig: "v1" };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// sjqz extract_wechat_key.py uses Memory.readCString(args[1]) for the
|
|
88
|
+
// key — meaning some WeChat builds pass the key as a NUL-terminated
|
|
89
|
+
// 64-char ASCII hex string. Other builds (and the original SQLCipher
|
|
90
|
+
// contract) pass 32 raw bytes. We can disambiguate by `len`:
|
|
91
|
+
// - len === 32 → raw 32-byte key → readByteArray + bytesToHex
|
|
92
|
+
// - len === 64 → ASCII hex string → readCString
|
|
93
|
+
// - anything else → emit error, host falls back to MD5 path
|
|
63
94
|
function makeHook(symbolName) {
|
|
95
|
+
var idx = argIndicesFor(symbolName);
|
|
64
96
|
return {
|
|
65
97
|
onEnter: function (args) {
|
|
66
98
|
if (fired) return;
|
|
99
|
+
if (idx.key < 0) {
|
|
100
|
+
send({
|
|
101
|
+
kind: "error",
|
|
102
|
+
message:
|
|
103
|
+
"unsupported symbol signature: " +
|
|
104
|
+
symbolName +
|
|
105
|
+
" — host should fall back to MD5(IMEI+UIN) key path",
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
67
109
|
try {
|
|
68
|
-
|
|
69
|
-
// args[1] = key bytes, args[2] = key length
|
|
70
|
-
var len = args[2].toInt32();
|
|
110
|
+
var len = args[idx.len].toInt32();
|
|
71
111
|
if (len <= 0 || len > 256) {
|
|
72
|
-
send({
|
|
112
|
+
send({
|
|
113
|
+
kind: "error",
|
|
114
|
+
message:
|
|
115
|
+
"implausible key length " + len + " at " + symbolName,
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
var hex;
|
|
120
|
+
var format;
|
|
121
|
+
if (len === 64) {
|
|
122
|
+
// ASCII hex string (sjqz-verified path on WeChat 7.x/8.0 libWCDB)
|
|
123
|
+
var s = Memory.readCString(args[idx.key], len);
|
|
124
|
+
if (!s || s.length === 0) {
|
|
125
|
+
send({
|
|
126
|
+
kind: "error",
|
|
127
|
+
message: "readCString returned empty at " + symbolName,
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
hex = s.toLowerCase();
|
|
132
|
+
format = "ascii-hex";
|
|
133
|
+
} else if (len === 32) {
|
|
134
|
+
// Raw 32-byte key — convert to 64-char hex
|
|
135
|
+
var buf = args[idx.key].readByteArray(len);
|
|
136
|
+
hex = bytesToHex(buf);
|
|
137
|
+
format = "raw-bytes";
|
|
138
|
+
} else {
|
|
139
|
+
// Ambiguous length — could be either. Emit both interpretations
|
|
140
|
+
// and let the host try each against the DB until one succeeds.
|
|
141
|
+
var bufAmb = args[idx.key].readByteArray(len);
|
|
142
|
+
var hexFromBytes = bytesToHex(bufAmb);
|
|
143
|
+
var hexFromString = null;
|
|
144
|
+
try {
|
|
145
|
+
var sAmb = Memory.readCString(args[idx.key], len);
|
|
146
|
+
if (sAmb) hexFromString = sAmb.toLowerCase();
|
|
147
|
+
} catch (_e) {
|
|
148
|
+
// readCString may fault on non-NUL-terminated bytes; ignore.
|
|
149
|
+
}
|
|
150
|
+
fired = true;
|
|
151
|
+
send({
|
|
152
|
+
kind: "key",
|
|
153
|
+
hex: hexFromBytes,
|
|
154
|
+
alt: hexFromString,
|
|
155
|
+
source: symbolName,
|
|
156
|
+
sig: idx.sig,
|
|
157
|
+
format: "ambiguous",
|
|
158
|
+
length: len,
|
|
159
|
+
});
|
|
73
160
|
return;
|
|
74
161
|
}
|
|
75
|
-
var buf = args[1].readByteArray(len);
|
|
76
|
-
var hex = bytesToHex(buf);
|
|
77
162
|
if (!hex) {
|
|
78
|
-
send({
|
|
163
|
+
send({
|
|
164
|
+
kind: "error",
|
|
165
|
+
message: "empty key buffer at " + symbolName,
|
|
166
|
+
});
|
|
79
167
|
return;
|
|
80
168
|
}
|
|
81
169
|
fired = true;
|
|
82
|
-
send({
|
|
170
|
+
send({
|
|
171
|
+
kind: "key",
|
|
172
|
+
hex: hex,
|
|
173
|
+
source: symbolName,
|
|
174
|
+
sig: idx.sig,
|
|
175
|
+
format: format,
|
|
176
|
+
length: len,
|
|
177
|
+
});
|
|
83
178
|
} catch (e) {
|
|
84
|
-
send({
|
|
179
|
+
send({
|
|
180
|
+
kind: "error",
|
|
181
|
+
message:
|
|
182
|
+
"hook exception at " +
|
|
183
|
+
symbolName +
|
|
184
|
+
": " +
|
|
185
|
+
(e && e.message ? e.message : String(e)),
|
|
186
|
+
});
|
|
85
187
|
}
|
|
86
188
|
},
|
|
87
189
|
};
|
|
88
190
|
}
|
|
89
191
|
|
|
90
|
-
function
|
|
91
|
-
var mod = Process.findModuleByName(
|
|
192
|
+
function tryAttachOnModule(moduleName) {
|
|
193
|
+
var mod = Process.findModuleByName(moduleName);
|
|
92
194
|
if (!mod) return false;
|
|
93
195
|
var attached = 0;
|
|
94
196
|
for (var i = 0; i < SYMBOLS.length; i++) {
|
|
95
|
-
var addr = Module.findExportByName(
|
|
197
|
+
var addr = Module.findExportByName(moduleName, SYMBOLS[i]);
|
|
96
198
|
if (!addr) continue;
|
|
97
199
|
try {
|
|
98
200
|
Interceptor.attach(addr, makeHook(SYMBOLS[i]));
|
|
99
|
-
send({ kind: "hooked", symbol: SYMBOLS[i], module:
|
|
201
|
+
send({ kind: "hooked", symbol: SYMBOLS[i], module: moduleName });
|
|
100
202
|
attached++;
|
|
101
203
|
} catch (e) {
|
|
102
|
-
send({
|
|
204
|
+
send({
|
|
205
|
+
kind: "error",
|
|
206
|
+
message:
|
|
207
|
+
"Interceptor.attach failed for " +
|
|
208
|
+
SYMBOLS[i] +
|
|
209
|
+
": " +
|
|
210
|
+
(e && e.message ? e.message : String(e)),
|
|
211
|
+
});
|
|
103
212
|
}
|
|
104
213
|
}
|
|
105
214
|
return attached > 0;
|
|
106
215
|
}
|
|
107
216
|
|
|
217
|
+
function tryAttach() {
|
|
218
|
+
for (var i = 0; i < TARGET_MODULES.length; i++) {
|
|
219
|
+
if (tryAttachOnModule(TARGET_MODULES[i])) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
108
226
|
// Module-load polling — §18.6 #1 "hook at module-load time before
|
|
109
|
-
// anti-detection thread runs". WeChat lazy-loads
|
|
227
|
+
// anti-detection thread runs". WeChat lazy-loads libWCDB when the
|
|
110
228
|
// first DB opens, so we can't always find it at script start.
|
|
111
229
|
if (!tryAttach()) {
|
|
112
|
-
send({ kind: "module-waiting", module:
|
|
230
|
+
send({ kind: "module-waiting", module: TARGET_MODULES.join("|") });
|
|
113
231
|
var attempts = 0;
|
|
114
232
|
var poll = function () {
|
|
115
233
|
attempts++;
|
|
116
234
|
if (tryAttach()) return;
|
|
117
235
|
if (attempts >= 60) {
|
|
118
236
|
// 60 attempts × 500ms = 30s ceiling, matches host timeoutMs
|
|
119
|
-
send({
|
|
237
|
+
send({
|
|
238
|
+
kind: "error",
|
|
239
|
+
message:
|
|
240
|
+
TARGET_MODULES.join("|") + " did not load within 30s",
|
|
241
|
+
});
|
|
120
242
|
return;
|
|
121
243
|
}
|
|
122
244
|
setTimeout(poll, 500);
|
|
@@ -191,6 +191,14 @@ class FridaKeyProvider extends KeyProvider {
|
|
|
191
191
|
if (evt.kind === "key") {
|
|
192
192
|
settled = true;
|
|
193
193
|
telemetry.keySource = evt.source;
|
|
194
|
+
// Phase 12.6 (post-sjqz audit) — capture sig/format/length so a
|
|
195
|
+
// failed DB open can be diagnosed: ascii-hex vs raw-bytes
|
|
196
|
+
// determines whether sqlite3_key got the expected key bytes,
|
|
197
|
+
// and sig=v1/v2 confirms args index resolution.
|
|
198
|
+
telemetry.keyFormat = evt.format || null;
|
|
199
|
+
telemetry.keySig = evt.sig || null;
|
|
200
|
+
telemetry.keyLength = evt.length || null;
|
|
201
|
+
telemetry.keyAlt = evt.alt || null;
|
|
194
202
|
telemetry.durationMs = Date.now() - telemetry.startedAt;
|
|
195
203
|
cleanup().then(() => resolve(String(evt.hex || "").toLowerCase()));
|
|
196
204
|
return;
|
|
@@ -203,11 +203,20 @@ function contactDisplayName(byUsername, wxid) {
|
|
|
203
203
|
function guessContactSubtype(row) {
|
|
204
204
|
// rcontact.type bits: official accounts / group / regular contact /
|
|
205
205
|
// black list. Detailed mapping in WeChat reverse-eng community —
|
|
206
|
-
// for v0.5 we keep it simple:
|
|
207
|
-
//
|
|
208
|
-
|
|
206
|
+
// for v0.5 we keep it simple: chatroom → unknown (not a Person),
|
|
207
|
+
// `gh_*` username → merchant (公众号 / Official Account — brand /
|
|
208
|
+
// business pushing content; closest enum match), rest → contact.
|
|
209
|
+
// Phase 12.6 will refine with full bit mapping + rcontact.type bits.
|
|
210
|
+
// (sjqz parity wechat.py:282 — get_friends() excludes gh_* from
|
|
211
|
+
// friends view but keeps them in contacts; we keep as Person with
|
|
212
|
+
// distinct subtype so Ask flow / EntityResolver can filter cleanly.)
|
|
213
|
+
if (typeof row.username !== "string") return "contact";
|
|
214
|
+
if (row.username.endsWith("@chatroom")) {
|
|
209
215
|
return "unknown"; // chat group, not a Person
|
|
210
216
|
}
|
|
217
|
+
if (row.username.startsWith("gh_")) {
|
|
218
|
+
return "merchant"; // 公众号 / Official Account
|
|
219
|
+
}
|
|
211
220
|
return "contact";
|
|
212
221
|
}
|
|
213
222
|
|
package/lib/index.js
CHANGED
|
@@ -39,10 +39,12 @@ const { Train12306Adapter } = require("./adapters/travel-12306");
|
|
|
39
39
|
const { CtripAdapter } = require("./adapters/travel-ctrip");
|
|
40
40
|
const { AmapAdapter } = require("./adapters/travel-amap");
|
|
41
41
|
const { BaiduMapAdapter } = require("./adapters/travel-baidu-map");
|
|
42
|
+
const { TencentMapAdapter } = require("./adapters/travel-tencent-map");
|
|
42
43
|
const shoppingBase = require("./adapters/shopping-base");
|
|
43
44
|
const { TaobaoAdapter } = require("./adapters/shopping-taobao");
|
|
44
45
|
const { JdAdapter } = require("./adapters/shopping-jd");
|
|
45
46
|
const { MeituanAdapter } = require("./adapters/shopping-meituan");
|
|
47
|
+
const { PinduoduoAdapter } = require("./adapters/shopping-pinduoduo");
|
|
46
48
|
const { BilibiliAdapter } = require("./adapters/social-bilibili");
|
|
47
49
|
const { WeiboAdapter } = require("./adapters/social-weibo");
|
|
48
50
|
const { DouyinAdapter } = require("./adapters/social-douyin");
|
|
@@ -221,13 +223,14 @@ module.exports = {
|
|
|
221
223
|
wxidToWeChatPersonId: wechatAdapter.wxidToWeChatPersonId,
|
|
222
224
|
WECHAT_PRAGMA_PROFILES: wechatAdapter.WECHAT_PRAGMA_PROFILES,
|
|
223
225
|
|
|
224
|
-
// Phase 9 — Travel
|
|
226
|
+
// Phase 9 + §2.5b 地图三联 — Travel five-pack
|
|
225
227
|
normalizeTravelRecord: travelBase.normalizeTravelRecord,
|
|
226
228
|
parseChineseDateTime: travelBase.parseChineseDateTime,
|
|
227
229
|
Train12306Adapter,
|
|
228
230
|
CtripAdapter,
|
|
229
231
|
AmapAdapter,
|
|
230
232
|
BaiduMapAdapter,
|
|
233
|
+
TencentMapAdapter,
|
|
231
234
|
|
|
232
235
|
// Phase 7 — Shopping three-pack
|
|
233
236
|
normalizeOrderRecord: shoppingBase.normalizeOrderRecord,
|
|
@@ -235,6 +238,7 @@ module.exports = {
|
|
|
235
238
|
TaobaoAdapter,
|
|
236
239
|
JdAdapter,
|
|
237
240
|
MeituanAdapter,
|
|
241
|
+
PinduoduoAdapter,
|
|
238
242
|
|
|
239
243
|
// Phase 13+ — long-tail social + messaging (借 sjqz parsers)
|
|
240
244
|
BilibiliAdapter,
|
package/lib/vault.js
CHANGED
|
@@ -44,19 +44,71 @@ function newGroupId() {
|
|
|
44
44
|
return `mg-${r()}${r()}-${Date.now().toString(36)}`;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Translate a bs3mc load-failure error into an actionable, user-readable
|
|
49
|
+
* message. Detects NODE_MODULE_VERSION mismatch (the single most common
|
|
50
|
+
* failure: Node 23/24/25 has no prebuild — bs3mc upstream only ships for
|
|
51
|
+
* Node LTS ABIs 108/115/127). See memory `node_23_native_dep_trap.md`.
|
|
52
|
+
*
|
|
53
|
+
* Pure function so it can be unit-tested without poisoning require cache.
|
|
54
|
+
*
|
|
55
|
+
* @param {Error|unknown} err Original throw from `require("better-sqlite3-multiple-ciphers")`.
|
|
56
|
+
* @param {string} [nodeVer] process.versions.node (override for tests).
|
|
57
|
+
* @returns {Error} Wrapped Error with `cause` and (when ABI-related) `code: "BS3MC_ABI_MISMATCH"`.
|
|
58
|
+
*/
|
|
59
|
+
function formatDriverLoadError(err, nodeVer) {
|
|
60
|
+
const originalMsg = err && err.message ? err.message : String(err);
|
|
61
|
+
const runtimeNodeVer = nodeVer || process.versions.node;
|
|
62
|
+
|
|
63
|
+
const abiMatch = originalMsg.match(
|
|
64
|
+
/NODE_MODULE_VERSION\s+(\d+)[\s\S]+?requires\s+NODE_MODULE_VERSION\s+(\d+)/,
|
|
65
|
+
);
|
|
66
|
+
if (abiMatch) {
|
|
67
|
+
const compiledAbi = abiMatch[1];
|
|
68
|
+
const runtimeAbi = abiMatch[2];
|
|
69
|
+
const lines = [
|
|
70
|
+
"better-sqlite3-multiple-ciphers ABI mismatch — Node " +
|
|
71
|
+
runtimeNodeVer +
|
|
72
|
+
" has ABI " +
|
|
73
|
+
runtimeAbi +
|
|
74
|
+
" but bs3mc prebuild is ABI " +
|
|
75
|
+
compiledAbi +
|
|
76
|
+
".",
|
|
77
|
+
"",
|
|
78
|
+
"修法(任选其一):",
|
|
79
|
+
" 1. 切 Node 22 LTS (推荐) — nvm-windows: `nvm install 22.12.0 && nvm use 22.12.0`",
|
|
80
|
+
" 2. 源码重编 — `npm rebuild better-sqlite3-multiple-ciphers --build-from-source`",
|
|
81
|
+
" (需要本机有 Visual Studio Build Tools / node-gyp toolchain,慢且不推荐)",
|
|
82
|
+
"",
|
|
83
|
+
"为什么 bs3mc 没 ABI " + runtimeAbi + " prebuild:",
|
|
84
|
+
" bs3mc 上游只 ship 主流 Node LTS 的 prebuild (ABI 108/115/127)。",
|
|
85
|
+
" Node 23/24/25 是 Current 系列,上游不给 prebuild。",
|
|
86
|
+
"",
|
|
87
|
+
"项目 engines.node 允许 >=22.12 是为了兼容未来 LTS,但实际推荐 22.x。",
|
|
88
|
+
];
|
|
89
|
+
const wrapped = new Error(lines.join("\n"));
|
|
90
|
+
wrapped.cause = err;
|
|
91
|
+
wrapped.code = "BS3MC_ABI_MISMATCH";
|
|
92
|
+
return wrapped;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const wrapped = new Error(
|
|
96
|
+
"Failed to load better-sqlite3-multiple-ciphers. " +
|
|
97
|
+
"Install it as a workspace dep or pin the version in your package. " +
|
|
98
|
+
"Original error: " +
|
|
99
|
+
originalMsg,
|
|
100
|
+
);
|
|
101
|
+
wrapped.cause = err;
|
|
102
|
+
return wrapped;
|
|
103
|
+
}
|
|
104
|
+
|
|
47
105
|
function loadDriver() {
|
|
48
106
|
// Lazy require so consumers that only need schemas don't pay for the
|
|
49
107
|
// native binding load. Errors surface here with a precise message.
|
|
50
108
|
try {
|
|
51
109
|
return require("better-sqlite3-multiple-ciphers");
|
|
52
110
|
} catch (err) {
|
|
53
|
-
|
|
54
|
-
"Failed to load better-sqlite3-multiple-ciphers. " +
|
|
55
|
-
"Install it as a workspace dep or pin the version in your package. " +
|
|
56
|
-
"Original error: " + (err && err.message ? err.message : String(err));
|
|
57
|
-
const wrapped = new Error(msg);
|
|
58
|
-
wrapped.cause = err;
|
|
59
|
-
throw wrapped;
|
|
111
|
+
throw formatDriverLoadError(err);
|
|
60
112
|
}
|
|
61
113
|
}
|
|
62
114
|
|
|
@@ -1223,4 +1275,4 @@ class LocalVault {
|
|
|
1223
1275
|
}
|
|
1224
1276
|
}
|
|
1225
1277
|
|
|
1226
|
-
module.exports = { LocalVault };
|
|
1278
|
+
module.exports = { LocalVault, _internal: { loadDriver, formatDriverLoadError } };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainlesschain/personal-data-hub",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
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",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"./adapters/travel-ctrip": "./lib/adapters/travel-ctrip/index.js",
|
|
47
47
|
"./adapters/travel-amap": "./lib/adapters/travel-amap/index.js",
|
|
48
48
|
"./adapters/travel-baidu-map": "./lib/adapters/travel-baidu-map/index.js",
|
|
49
|
+
"./adapters/travel-tencent-map": "./lib/adapters/travel-tencent-map/index.js",
|
|
49
50
|
"./adapters/shopping-base": "./lib/adapters/shopping-base/index.js",
|
|
50
51
|
"./adapters/shopping-taobao": "./lib/adapters/shopping-taobao/index.js",
|
|
51
52
|
"./adapters/shopping-jd": "./lib/adapters/shopping-jd/index.js",
|