chatlab-cli 0.27.2 → 0.28.0
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/README.md +1 -1
- package/dist/{chat-command-QVCZVDSB.mjs → chat-command-7WL5NMZ6.mjs} +5 -5
- package/dist/{chunk-B2VLK3FB.mjs → chunk-55WR6WKW.mjs} +50 -18
- package/dist/{chunk-B2VLK3FB.mjs.map → chunk-55WR6WKW.mjs.map} +1 -1
- package/dist/{chunk-K7UUN3HT.mjs → chunk-GFRG7TZQ.mjs} +27 -12
- package/dist/chunk-GFRG7TZQ.mjs.map +1 -0
- package/dist/{chunk-DHRSLYUM.mjs → chunk-GPF34WXV.mjs} +2470 -330
- package/dist/chunk-GPF34WXV.mjs.map +1 -0
- package/dist/{chunk-OD3YH23N.mjs → chunk-VASK54KT.mjs} +2 -2
- package/dist/{chunk-H22VDCPB.mjs → chunk-WGS33EWH.mjs} +2 -2
- package/dist/{chunk-PXWAYFII.mjs → chunk-XNU5X7EV.mjs} +3 -3
- package/dist/{chunk-JOXF6ROV.mjs → chunk-YQ2FJGBT.mjs} +137 -18
- package/dist/chunk-YQ2FJGBT.mjs.map +1 -0
- package/dist/{chunk-ST5APJB2.mjs → chunk-YZDEZ6UI.mjs} +3 -3
- package/dist/{chunk-MDDWX2MG.mjs → chunk-ZSFVX6FM.mjs} +3 -3
- package/dist/cli.mjs +4 -4
- package/dist/{http-LSCVGWCI.mjs → http-C2FBHNZG.mjs} +9 -9
- package/dist/{import-E6HBJMMT.mjs → import-ED6JCPSJ.mjs} +5 -5
- package/dist/index.mjs +9 -9
- package/dist/{mcp-I7JUC5JV.mjs → mcp-5JIBER4M.mjs} +5 -5
- package/dist/semantic-index-worker.mjs +1 -1
- package/dist/{src-HZILDI7C.mjs → src-WBNM42SL.mjs} +19 -3
- package/dist/{stream-import-IMRULRS2.mjs → stream-import-37U3SROO.mjs} +4 -4
- package/dist/{worker-runtime-WWQ7W74Q.mjs → worker-runtime-6DGYL4TF.mjs} +2 -2
- package/dist-web/assets/{DebugToolsPanel.vue_vue_type_script_setup_true_lang-Du1FDD8L.js → DebugToolsPanel.vue_vue_type_script_setup_true_lang-CCz0Syxo.js} +5 -5
- package/dist-web/assets/{MessageExportModal-4ehLHG4x.js → MessageExportModal-Dd6R-cX_.js} +1 -1
- package/dist-web/assets/electron-D9vE5t3H.js +1 -0
- package/dist-web/assets/{electron-B3AteJC8.js → electron-DjminAKK.js} +1 -1
- package/dist-web/assets/{fetch-BUcl-Frr.js → fetch-B_kLRm6-.js} +1 -1
- package/dist-web/assets/{fetch-DZFx8FA4.js → fetch-CURbMNJV.js} +1 -1
- package/dist-web/assets/fetch-Cle6QKmL.js +3 -0
- package/dist-web/assets/{fetch-BQxv_UGQ.js → fetch-DFCYOQe5.js} +1 -1
- package/dist-web/assets/{fetch-ChZEF_n3.js → fetch-DOhCQ5J8.js} +1 -1
- package/dist-web/assets/{fetch-BwQh9WUD.js → fetch-DV8A1dGB.js} +1 -1
- package/dist-web/assets/{fetch-DlJFgbum.js → fetch-Wad5mWVH.js} +1 -1
- package/dist-web/assets/{fetch-DCQN6wfR.js → fetch-r83wdzHy.js} +1 -1
- package/dist-web/assets/{fetch-CZDFhvxY.js → fetch-srCJzcWc.js} +1 -1
- package/dist-web/assets/{fetch-C2mSdG3h.js → fetch-uM3erGZm.js} +1 -1
- package/dist-web/assets/index-7E5GSvR2.css +1 -0
- package/dist-web/assets/index-BCRHSc1k.js +173 -0
- package/dist-web/assets/{index-DlkH2E7N.js → index-BIvLzdwg.js} +1 -1
- package/dist-web/assets/{index-qVTX1tLg.js → index-BpszRZ8V.js} +3 -3
- package/dist-web/assets/index-D5UgZUpS.js +12 -0
- package/dist-web/assets/{index-DTlfOd_u.js → index-hOsKRsp6.js} +2 -2
- package/dist-web/assets/{index-KAFPL6dl.js → index-tkbEq8av.js} +1 -1
- package/dist-web/assets/{web-CoKgy4Oo.js → web-D27K6zSX.js} +1 -1
- package/dist-web/index.html +2 -2
- package/package.json +1 -1
- package/dist/chunk-DHRSLYUM.mjs.map +0 -1
- package/dist/chunk-JOXF6ROV.mjs.map +0 -1
- package/dist/chunk-K7UUN3HT.mjs.map +0 -1
- package/dist-web/assets/electron-2m4Vdk2z.js +0 -1
- package/dist-web/assets/fetch-O8M5ZWsc.js +0 -3
- package/dist-web/assets/index-B_uZZGqi.js +0 -173
- package/dist-web/assets/index-CoX0L-A8.css +0 -1
- package/dist-web/assets/index-DR78oafF.js +0 -11
- /package/dist/{chat-command-QVCZVDSB.mjs.map → chat-command-7WL5NMZ6.mjs.map} +0 -0
- /package/dist/{chunk-OD3YH23N.mjs.map → chunk-VASK54KT.mjs.map} +0 -0
- /package/dist/{chunk-H22VDCPB.mjs.map → chunk-WGS33EWH.mjs.map} +0 -0
- /package/dist/{chunk-PXWAYFII.mjs.map → chunk-XNU5X7EV.mjs.map} +0 -0
- /package/dist/{chunk-ST5APJB2.mjs.map → chunk-YZDEZ6UI.mjs.map} +0 -0
- /package/dist/{chunk-MDDWX2MG.mjs.map → chunk-ZSFVX6FM.mjs.map} +0 -0
- /package/dist/{http-LSCVGWCI.mjs.map → http-C2FBHNZG.mjs.map} +0 -0
- /package/dist/{import-E6HBJMMT.mjs.map → import-ED6JCPSJ.mjs.map} +0 -0
- /package/dist/{mcp-I7JUC5JV.mjs.map → mcp-5JIBER4M.mjs.map} +0 -0
- /package/dist/{src-HZILDI7C.mjs.map → src-WBNM42SL.mjs.map} +0 -0
- /package/dist/{stream-import-IMRULRS2.mjs.map → stream-import-37U3SROO.mjs.map} +0 -0
- /package/dist/{worker-runtime-WWQ7W74Q.mjs.map → worker-runtime-6DGYL4TF.mjs.map} +0 -0
|
@@ -51,6 +51,8 @@ import {
|
|
|
51
51
|
deriveParentId,
|
|
52
52
|
detectConflictsInMessages,
|
|
53
53
|
estimateTokens,
|
|
54
|
+
extractErrorInfo,
|
|
55
|
+
extractErrorStack,
|
|
54
56
|
extractFtsKeywords,
|
|
55
57
|
formatEvidenceMessages,
|
|
56
58
|
generateMessageKey,
|
|
@@ -82,7 +84,7 @@ import {
|
|
|
82
84
|
vecTableName,
|
|
83
85
|
vecTableSchema,
|
|
84
86
|
writeConfigField
|
|
85
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-55WR6WKW.mjs";
|
|
86
88
|
import {
|
|
87
89
|
__commonJS,
|
|
88
90
|
__export,
|
|
@@ -97,8 +99,8 @@ var require_Utf8Stream = __commonJS({
|
|
|
97
99
|
var { Transform } = __require("stream");
|
|
98
100
|
var { StringDecoder } = __require("string_decoder");
|
|
99
101
|
var Utf8Stream = class extends Transform {
|
|
100
|
-
constructor(
|
|
101
|
-
super(Object.assign({},
|
|
102
|
+
constructor(options2) {
|
|
103
|
+
super(Object.assign({}, options2, { writableObjectMode: false }));
|
|
102
104
|
this._buffer = "";
|
|
103
105
|
}
|
|
104
106
|
_transform(chunk, encoding, callback) {
|
|
@@ -178,22 +180,22 @@ var require_Parser = __commonJS({
|
|
|
178
180
|
var fromHex = (s) => String.fromCharCode(parseInt(s.slice(2), 16));
|
|
179
181
|
var codes = { b: "\b", f: "\f", n: "\n", r: "\r", t: " ", '"': '"', "\\": "\\", "/": "/" };
|
|
180
182
|
var Parser = class _Parser extends Utf8Stream {
|
|
181
|
-
static make(
|
|
182
|
-
return new _Parser(
|
|
183
|
+
static make(options2) {
|
|
184
|
+
return new _Parser(options2);
|
|
183
185
|
}
|
|
184
|
-
constructor(
|
|
185
|
-
super(Object.assign({},
|
|
186
|
+
constructor(options2) {
|
|
187
|
+
super(Object.assign({}, options2, { readableObjectMode: true }));
|
|
186
188
|
this._packKeys = this._packStrings = this._packNumbers = this._streamKeys = this._streamStrings = this._streamNumbers = true;
|
|
187
|
-
if (
|
|
188
|
-
"packValues" in
|
|
189
|
-
"packKeys" in
|
|
190
|
-
"packStrings" in
|
|
191
|
-
"packNumbers" in
|
|
192
|
-
"streamValues" in
|
|
193
|
-
"streamKeys" in
|
|
194
|
-
"streamStrings" in
|
|
195
|
-
"streamNumbers" in
|
|
196
|
-
this._jsonStreaming =
|
|
189
|
+
if (options2) {
|
|
190
|
+
"packValues" in options2 && (this._packKeys = this._packStrings = this._packNumbers = options2.packValues);
|
|
191
|
+
"packKeys" in options2 && (this._packKeys = options2.packKeys);
|
|
192
|
+
"packStrings" in options2 && (this._packStrings = options2.packStrings);
|
|
193
|
+
"packNumbers" in options2 && (this._packNumbers = options2.packNumbers);
|
|
194
|
+
"streamValues" in options2 && (this._streamKeys = this._streamStrings = this._streamNumbers = options2.streamValues);
|
|
195
|
+
"streamKeys" in options2 && (this._streamKeys = options2.streamKeys);
|
|
196
|
+
"streamStrings" in options2 && (this._streamStrings = options2.streamStrings);
|
|
197
|
+
"streamNumbers" in options2 && (this._streamNumbers = options2.streamNumbers);
|
|
198
|
+
this._jsonStreaming = options2.jsonStreaming;
|
|
197
199
|
}
|
|
198
200
|
!this._packKeys && (this._streamKeys = true);
|
|
199
201
|
!this._packStrings && (this._streamStrings = true);
|
|
@@ -683,7 +685,7 @@ var require_stream_json = __commonJS({
|
|
|
683
685
|
"use strict";
|
|
684
686
|
var Parser = require_Parser();
|
|
685
687
|
var emit = require_emit();
|
|
686
|
-
var make = (
|
|
688
|
+
var make = (options2) => emit(new Parser(options2));
|
|
687
689
|
make.Parser = Parser;
|
|
688
690
|
make.parser = Parser.parser;
|
|
689
691
|
module.exports = make;
|
|
@@ -698,8 +700,8 @@ var require_FilterBase = __commonJS({
|
|
|
698
700
|
var FilterBase = class _FilterBase extends Transform {
|
|
699
701
|
static stringFilter(string, separator) {
|
|
700
702
|
return (stack) => {
|
|
701
|
-
const
|
|
702
|
-
return
|
|
703
|
+
const path24 = stack.join(separator);
|
|
704
|
+
return path24.length === string.length && path24 === string || path24.length > string.length && path24.substr(0, string.length) === string && path24.substr(string.length, separator.length) === separator;
|
|
703
705
|
};
|
|
704
706
|
}
|
|
705
707
|
static regExpFilter(regExp, separator) {
|
|
@@ -708,11 +710,11 @@ var require_FilterBase = __commonJS({
|
|
|
708
710
|
static arrayReplacement(array) {
|
|
709
711
|
return () => array;
|
|
710
712
|
}
|
|
711
|
-
constructor(
|
|
712
|
-
super(Object.assign({},
|
|
713
|
+
constructor(options2) {
|
|
714
|
+
super(Object.assign({}, options2, { writableObjectMode: true, readableObjectMode: true }));
|
|
713
715
|
this._transform = this._check;
|
|
714
716
|
this._stack = [];
|
|
715
|
-
const filter =
|
|
717
|
+
const filter = options2 && options2.filter, separator = options2 && options2.pathSeparator || ".";
|
|
716
718
|
if (typeof filter == "string") {
|
|
717
719
|
this._filter = _FilterBase.stringFilter(filter, separator);
|
|
718
720
|
} else if (typeof filter == "function") {
|
|
@@ -720,19 +722,19 @@ var require_FilterBase = __commonJS({
|
|
|
720
722
|
} else if (filter instanceof RegExp) {
|
|
721
723
|
this._filter = _FilterBase.regExpFilter(filter, separator);
|
|
722
724
|
}
|
|
723
|
-
const replacement =
|
|
725
|
+
const replacement = options2 && options2.replacement;
|
|
724
726
|
if (typeof replacement == "function") {
|
|
725
727
|
this._replacement = replacement;
|
|
726
728
|
} else {
|
|
727
729
|
this._replacement = _FilterBase.arrayReplacement(replacement || _FilterBase.defaultReplacement);
|
|
728
730
|
}
|
|
729
|
-
this._allowEmptyReplacement =
|
|
731
|
+
this._allowEmptyReplacement = options2 && options2.allowEmptyReplacement;
|
|
730
732
|
this._streamKeys = true;
|
|
731
|
-
if (
|
|
732
|
-
"streamValues" in
|
|
733
|
-
"streamKeys" in
|
|
733
|
+
if (options2) {
|
|
734
|
+
"streamValues" in options2 && (this._streamKeys = options2.streamValues);
|
|
735
|
+
"streamKeys" in options2 && (this._streamKeys = options2.streamKeys);
|
|
734
736
|
}
|
|
735
|
-
this._once =
|
|
737
|
+
this._once = options2 && options2.once;
|
|
736
738
|
this._previousToken = "";
|
|
737
739
|
}
|
|
738
740
|
_check(chunk, _, callback) {
|
|
@@ -950,8 +952,8 @@ var require_stream_chain = __commonJS({
|
|
|
950
952
|
var isWritableNodeStream = (obj) => obj && typeof obj.write === "function" && typeof obj.on === "function" && (!obj._readableState || (typeof obj._writableState === "object" ? obj._writableState.writable : null) !== false);
|
|
951
953
|
var isDuplexNodeStream = (obj) => obj && typeof obj.pipe === "function" && obj._readableState && typeof obj.on === "function" && typeof obj.write === "function";
|
|
952
954
|
var Chain = class _Chain extends Duplex {
|
|
953
|
-
constructor(fns,
|
|
954
|
-
super(
|
|
955
|
+
constructor(fns, options2) {
|
|
956
|
+
super(options2 || { writableObjectMode: true, readableObjectMode: true });
|
|
955
957
|
if (!(fns instanceof Array) || !fns.length) {
|
|
956
958
|
throw Error("Chain's argument should be a non-empty array.");
|
|
957
959
|
}
|
|
@@ -978,7 +980,7 @@ var require_stream_chain = __commonJS({
|
|
|
978
980
|
this.resume();
|
|
979
981
|
this.output.on("finish", () => this.push(null));
|
|
980
982
|
}
|
|
981
|
-
if (!
|
|
983
|
+
if (!options2 || !options2.skipEvents) {
|
|
982
984
|
this.streams.forEach((stream) => stream.on("error", (error) => this.emit("error", error)));
|
|
983
985
|
}
|
|
984
986
|
}
|
|
@@ -1001,8 +1003,8 @@ var require_stream_chain = __commonJS({
|
|
|
1001
1003
|
_read() {
|
|
1002
1004
|
this.output.resume();
|
|
1003
1005
|
}
|
|
1004
|
-
static make(fns,
|
|
1005
|
-
return new _Chain(fns,
|
|
1006
|
+
static make(fns, options2) {
|
|
1007
|
+
return new _Chain(fns, options2);
|
|
1006
1008
|
}
|
|
1007
1009
|
static sanitize(result, stream) {
|
|
1008
1010
|
if (_Chain.isFinal(result)) {
|
|
@@ -1041,9 +1043,9 @@ var require_stream_chain = __commonJS({
|
|
|
1041
1043
|
var require_withParser = __commonJS({
|
|
1042
1044
|
"../../node_modules/stream-json/utils/withParser.js"(exports, module) {
|
|
1043
1045
|
"use strict";
|
|
1044
|
-
var { chain:
|
|
1046
|
+
var { chain: chain10 } = require_stream_chain();
|
|
1045
1047
|
var Parser = require_Parser();
|
|
1046
|
-
var withParser = (fn,
|
|
1048
|
+
var withParser = (fn, options2) => chain10([new Parser(options2), fn(options2)], Object.assign({}, options2, { writableObjectMode: false, readableObjectMode: true }));
|
|
1047
1049
|
module.exports = withParser;
|
|
1048
1050
|
}
|
|
1049
1051
|
});
|
|
@@ -1055,11 +1057,11 @@ var require_Pick = __commonJS({
|
|
|
1055
1057
|
var FilterBase = require_FilterBase();
|
|
1056
1058
|
var withParser = require_withParser();
|
|
1057
1059
|
var Pick = class _Pick extends FilterBase {
|
|
1058
|
-
static make(
|
|
1059
|
-
return new _Pick(
|
|
1060
|
+
static make(options2) {
|
|
1061
|
+
return new _Pick(options2);
|
|
1060
1062
|
}
|
|
1061
|
-
static withParser(
|
|
1062
|
-
return withParser(_Pick.make,
|
|
1063
|
+
static withParser(options2) {
|
|
1064
|
+
return withParser(_Pick.make, options2);
|
|
1063
1065
|
}
|
|
1064
1066
|
_checkChunk(chunk) {
|
|
1065
1067
|
switch (chunk.name) {
|
|
@@ -1122,20 +1124,20 @@ var require_Assembler = __commonJS({
|
|
|
1122
1124
|
this.key = null;
|
|
1123
1125
|
};
|
|
1124
1126
|
var Assembler = class _Assembler extends EventEmitter {
|
|
1125
|
-
static connectTo(stream,
|
|
1126
|
-
return new _Assembler(
|
|
1127
|
+
static connectTo(stream, options2) {
|
|
1128
|
+
return new _Assembler(options2).connectTo(stream);
|
|
1127
1129
|
}
|
|
1128
|
-
constructor(
|
|
1130
|
+
constructor(options2) {
|
|
1129
1131
|
super();
|
|
1130
1132
|
this.stack = [];
|
|
1131
1133
|
this.current = this.key = null;
|
|
1132
1134
|
this.done = true;
|
|
1133
|
-
if (
|
|
1134
|
-
this.reviver = typeof
|
|
1135
|
+
if (options2) {
|
|
1136
|
+
this.reviver = typeof options2.reviver == "function" && options2.reviver;
|
|
1135
1137
|
if (this.reviver) {
|
|
1136
1138
|
this.stringValue = this._saveValue = this._saveValueWithReviver;
|
|
1137
1139
|
}
|
|
1138
|
-
if (
|
|
1140
|
+
if (options2.numberAsString) {
|
|
1139
1141
|
this.numberValue = this.stringValue;
|
|
1140
1142
|
}
|
|
1141
1143
|
}
|
|
@@ -1153,12 +1155,12 @@ var require_Assembler = __commonJS({
|
|
|
1153
1155
|
return (this.stack.length >> 1) + (this.done ? 0 : 1);
|
|
1154
1156
|
}
|
|
1155
1157
|
get path() {
|
|
1156
|
-
const
|
|
1158
|
+
const path24 = [];
|
|
1157
1159
|
for (let i = 0; i < this.stack.length; i += 2) {
|
|
1158
1160
|
const key = this.stack[i + 1];
|
|
1159
|
-
|
|
1161
|
+
path24.push(key === null ? this.stack[i].length : key);
|
|
1160
1162
|
}
|
|
1161
|
-
return
|
|
1163
|
+
return path24;
|
|
1162
1164
|
}
|
|
1163
1165
|
dropToLevel(level) {
|
|
1164
1166
|
if (level < this.depth) {
|
|
@@ -1272,17 +1274,17 @@ var require_StreamBase = __commonJS({
|
|
|
1272
1274
|
}
|
|
1273
1275
|
};
|
|
1274
1276
|
var StreamBase = class extends Transform {
|
|
1275
|
-
constructor(
|
|
1276
|
-
super(Object.assign({},
|
|
1277
|
-
if (
|
|
1278
|
-
this.objectFilter =
|
|
1279
|
-
this.includeUndecided =
|
|
1277
|
+
constructor(options2) {
|
|
1278
|
+
super(Object.assign({}, options2, { writableObjectMode: true, readableObjectMode: true }));
|
|
1279
|
+
if (options2) {
|
|
1280
|
+
this.objectFilter = options2.objectFilter;
|
|
1281
|
+
this.includeUndecided = options2.includeUndecided;
|
|
1280
1282
|
}
|
|
1281
1283
|
if (typeof this.objectFilter != "function") {
|
|
1282
1284
|
this._filter = this._transform;
|
|
1283
1285
|
}
|
|
1284
1286
|
this._transform = this._wait || this._filter;
|
|
1285
|
-
this._assembler = new Assembler(
|
|
1287
|
+
this._assembler = new Assembler(options2);
|
|
1286
1288
|
}
|
|
1287
1289
|
_transform(chunk, encoding, callback) {
|
|
1288
1290
|
if (this._assembler[chunk.name]) {
|
|
@@ -1354,14 +1356,14 @@ var require_StreamValues = __commonJS({
|
|
|
1354
1356
|
var StreamBase = require_StreamBase();
|
|
1355
1357
|
var withParser = require_withParser();
|
|
1356
1358
|
var StreamValues = class _StreamValues extends StreamBase {
|
|
1357
|
-
static make(
|
|
1358
|
-
return new _StreamValues(
|
|
1359
|
+
static make(options2) {
|
|
1360
|
+
return new _StreamValues(options2);
|
|
1359
1361
|
}
|
|
1360
|
-
static withParser(
|
|
1361
|
-
return withParser(_StreamValues.make, Object.assign({},
|
|
1362
|
+
static withParser(options2) {
|
|
1363
|
+
return withParser(_StreamValues.make, Object.assign({}, options2, { jsonStreaming: true }));
|
|
1362
1364
|
}
|
|
1363
|
-
constructor(
|
|
1364
|
-
super(
|
|
1365
|
+
constructor(options2) {
|
|
1366
|
+
super(options2);
|
|
1365
1367
|
this._counter = 0;
|
|
1366
1368
|
this._level = 0;
|
|
1367
1369
|
}
|
|
@@ -1380,6 +1382,1353 @@ var require_StreamValues = __commonJS({
|
|
|
1380
1382
|
}
|
|
1381
1383
|
});
|
|
1382
1384
|
|
|
1385
|
+
// ../../node_modules/pend/index.js
|
|
1386
|
+
var require_pend = __commonJS({
|
|
1387
|
+
"../../node_modules/pend/index.js"(exports, module) {
|
|
1388
|
+
"use strict";
|
|
1389
|
+
module.exports = Pend;
|
|
1390
|
+
function Pend() {
|
|
1391
|
+
this.pending = 0;
|
|
1392
|
+
this.max = Infinity;
|
|
1393
|
+
this.listeners = [];
|
|
1394
|
+
this.waiting = [];
|
|
1395
|
+
this.error = null;
|
|
1396
|
+
}
|
|
1397
|
+
Pend.prototype.go = function(fn) {
|
|
1398
|
+
if (this.pending < this.max) {
|
|
1399
|
+
pendGo(this, fn);
|
|
1400
|
+
} else {
|
|
1401
|
+
this.waiting.push(fn);
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
Pend.prototype.wait = function(cb) {
|
|
1405
|
+
if (this.pending === 0) {
|
|
1406
|
+
cb(this.error);
|
|
1407
|
+
} else {
|
|
1408
|
+
this.listeners.push(cb);
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
Pend.prototype.hold = function() {
|
|
1412
|
+
return pendHold(this);
|
|
1413
|
+
};
|
|
1414
|
+
function pendHold(self) {
|
|
1415
|
+
self.pending += 1;
|
|
1416
|
+
var called = false;
|
|
1417
|
+
return onCb;
|
|
1418
|
+
function onCb(err) {
|
|
1419
|
+
if (called) throw new Error("callback called twice");
|
|
1420
|
+
called = true;
|
|
1421
|
+
self.error = self.error || err;
|
|
1422
|
+
self.pending -= 1;
|
|
1423
|
+
if (self.waiting.length > 0 && self.pending < self.max) {
|
|
1424
|
+
pendGo(self, self.waiting.shift());
|
|
1425
|
+
} else if (self.pending === 0) {
|
|
1426
|
+
var listeners = self.listeners;
|
|
1427
|
+
self.listeners = [];
|
|
1428
|
+
listeners.forEach(cbListener);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
function cbListener(listener) {
|
|
1432
|
+
listener(self.error);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
function pendGo(self, fn) {
|
|
1436
|
+
fn(pendHold(self));
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
});
|
|
1440
|
+
|
|
1441
|
+
// ../../packages/node-runtime/node_modules/yauzl/fd-slicer.js
|
|
1442
|
+
var require_fd_slicer = __commonJS({
|
|
1443
|
+
"../../packages/node-runtime/node_modules/yauzl/fd-slicer.js"(exports) {
|
|
1444
|
+
"use strict";
|
|
1445
|
+
var fs29 = __require("fs");
|
|
1446
|
+
var util = __require("util");
|
|
1447
|
+
var stream = __require("stream");
|
|
1448
|
+
var Readable = stream.Readable;
|
|
1449
|
+
var PassThrough = stream.PassThrough;
|
|
1450
|
+
var Pend = require_pend();
|
|
1451
|
+
var EventEmitter = __require("events").EventEmitter;
|
|
1452
|
+
exports.BufferSlicer = BufferSlicer;
|
|
1453
|
+
exports.FdSlicer = FdSlicer;
|
|
1454
|
+
util.inherits(FdSlicer, EventEmitter);
|
|
1455
|
+
function FdSlicer(fd) {
|
|
1456
|
+
EventEmitter.call(this);
|
|
1457
|
+
this.fd = fd;
|
|
1458
|
+
this.pend = new Pend();
|
|
1459
|
+
this.pend.max = 1;
|
|
1460
|
+
this.refCount = 0;
|
|
1461
|
+
}
|
|
1462
|
+
FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
|
|
1463
|
+
var self = this;
|
|
1464
|
+
self.pend.go(function(cb) {
|
|
1465
|
+
fs29.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
|
|
1466
|
+
cb();
|
|
1467
|
+
callback(err, bytesRead, buffer2);
|
|
1468
|
+
});
|
|
1469
|
+
});
|
|
1470
|
+
};
|
|
1471
|
+
FdSlicer.prototype.createReadStream = function(options2) {
|
|
1472
|
+
return new ReadStream(this, options2);
|
|
1473
|
+
};
|
|
1474
|
+
FdSlicer.prototype.ref = function() {
|
|
1475
|
+
this.refCount += 1;
|
|
1476
|
+
};
|
|
1477
|
+
FdSlicer.prototype.unref = function() {
|
|
1478
|
+
var self = this;
|
|
1479
|
+
self.refCount -= 1;
|
|
1480
|
+
if (self.refCount < 0) throw new Error("invalid unref");
|
|
1481
|
+
if (self.refCount > 0) return;
|
|
1482
|
+
fs29.close(self.fd, onCloseDone);
|
|
1483
|
+
function onCloseDone(err) {
|
|
1484
|
+
if (err) {
|
|
1485
|
+
self.emit("error", err);
|
|
1486
|
+
} else {
|
|
1487
|
+
self.emit("close");
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
util.inherits(ReadStream, Readable);
|
|
1492
|
+
function ReadStream(context, options2) {
|
|
1493
|
+
options2 = options2 || {};
|
|
1494
|
+
Readable.call(this, options2);
|
|
1495
|
+
this.context = context;
|
|
1496
|
+
this.context.ref();
|
|
1497
|
+
this.start = options2.start || 0;
|
|
1498
|
+
this.endOffset = options2.end;
|
|
1499
|
+
this.pos = this.start;
|
|
1500
|
+
}
|
|
1501
|
+
ReadStream.prototype._read = function(n) {
|
|
1502
|
+
var self = this;
|
|
1503
|
+
var toRead = Math.min(self._readableState.highWaterMark, n);
|
|
1504
|
+
if (self.endOffset != null) {
|
|
1505
|
+
toRead = Math.min(toRead, self.endOffset - self.pos);
|
|
1506
|
+
}
|
|
1507
|
+
if (toRead <= 0) {
|
|
1508
|
+
self.push(null);
|
|
1509
|
+
this._cleanup();
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
self.context.pend.go(function(cb) {
|
|
1513
|
+
var buffer = Buffer.allocUnsafe(toRead);
|
|
1514
|
+
fs29.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
|
|
1515
|
+
if (err) {
|
|
1516
|
+
self.destroy(err);
|
|
1517
|
+
} else if (bytesRead === 0) {
|
|
1518
|
+
self.push(null);
|
|
1519
|
+
self._cleanup();
|
|
1520
|
+
} else {
|
|
1521
|
+
self.pos += bytesRead;
|
|
1522
|
+
self.push(buffer.slice(0, bytesRead));
|
|
1523
|
+
}
|
|
1524
|
+
cb();
|
|
1525
|
+
});
|
|
1526
|
+
});
|
|
1527
|
+
};
|
|
1528
|
+
ReadStream.prototype._destroy = function(err, cb) {
|
|
1529
|
+
this._cleanup();
|
|
1530
|
+
cb(err);
|
|
1531
|
+
};
|
|
1532
|
+
ReadStream.prototype._cleanup = function() {
|
|
1533
|
+
if (this.context != null) {
|
|
1534
|
+
this.context.unref();
|
|
1535
|
+
this.context = null;
|
|
1536
|
+
}
|
|
1537
|
+
};
|
|
1538
|
+
util.inherits(BufferSlicer, EventEmitter);
|
|
1539
|
+
function BufferSlicer(buffer) {
|
|
1540
|
+
EventEmitter.call(this);
|
|
1541
|
+
this.refCount = 0;
|
|
1542
|
+
this.buffer = buffer;
|
|
1543
|
+
}
|
|
1544
|
+
BufferSlicer.prototype.read = function(buffer, offset, length, position, callback) {
|
|
1545
|
+
if (!(0 <= offset && offset <= buffer.length)) throw new RangeError("offset outside buffer: 0 <= " + offset + " <= " + buffer.length);
|
|
1546
|
+
if (position < 0) throw new RangeError("position is negative: " + position);
|
|
1547
|
+
if (offset + length > buffer.length) {
|
|
1548
|
+
length = buffer.length - offset;
|
|
1549
|
+
}
|
|
1550
|
+
if (position + length > this.buffer.length) {
|
|
1551
|
+
length = this.buffer.length - position;
|
|
1552
|
+
}
|
|
1553
|
+
if (length <= 0) {
|
|
1554
|
+
setImmediate(function() {
|
|
1555
|
+
callback(null, 0);
|
|
1556
|
+
});
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
this.buffer.copy(buffer, offset, position, position + length);
|
|
1560
|
+
setImmediate(function() {
|
|
1561
|
+
callback(null, length);
|
|
1562
|
+
});
|
|
1563
|
+
};
|
|
1564
|
+
BufferSlicer.prototype.createReadStream = function(options2) {
|
|
1565
|
+
options2 = options2 || {};
|
|
1566
|
+
var readStream = new PassThrough(options2);
|
|
1567
|
+
readStream.start = options2.start || 0;
|
|
1568
|
+
readStream.endOffset = options2.end;
|
|
1569
|
+
readStream.pos = readStream.endOffset || this.buffer.length;
|
|
1570
|
+
var entireSlice = this.buffer.slice(readStream.start, readStream.pos);
|
|
1571
|
+
var maxChunkSize = 65536;
|
|
1572
|
+
var offset = 0;
|
|
1573
|
+
while (true) {
|
|
1574
|
+
var nextOffset = offset + maxChunkSize;
|
|
1575
|
+
if (nextOffset >= entireSlice.length) {
|
|
1576
|
+
if (offset < entireSlice.length) {
|
|
1577
|
+
readStream.write(entireSlice.slice(offset, entireSlice.length));
|
|
1578
|
+
}
|
|
1579
|
+
break;
|
|
1580
|
+
}
|
|
1581
|
+
readStream.write(entireSlice.slice(offset, nextOffset));
|
|
1582
|
+
offset = nextOffset;
|
|
1583
|
+
}
|
|
1584
|
+
readStream.end();
|
|
1585
|
+
return readStream;
|
|
1586
|
+
};
|
|
1587
|
+
BufferSlicer.prototype.ref = function() {
|
|
1588
|
+
this.refCount += 1;
|
|
1589
|
+
};
|
|
1590
|
+
BufferSlicer.prototype.unref = function() {
|
|
1591
|
+
this.refCount -= 1;
|
|
1592
|
+
if (this.refCount < 0) {
|
|
1593
|
+
throw new Error("invalid unref");
|
|
1594
|
+
}
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
});
|
|
1598
|
+
|
|
1599
|
+
// ../../packages/node-runtime/node_modules/yauzl/crc32.js
|
|
1600
|
+
var require_crc32 = __commonJS({
|
|
1601
|
+
"../../packages/node-runtime/node_modules/yauzl/crc32.js"(exports, module) {
|
|
1602
|
+
"use strict";
|
|
1603
|
+
var CRC_TABLE = new Int32Array([
|
|
1604
|
+
0,
|
|
1605
|
+
1996959894,
|
|
1606
|
+
3993919788,
|
|
1607
|
+
2567524794,
|
|
1608
|
+
124634137,
|
|
1609
|
+
1886057615,
|
|
1610
|
+
3915621685,
|
|
1611
|
+
2657392035,
|
|
1612
|
+
249268274,
|
|
1613
|
+
2044508324,
|
|
1614
|
+
3772115230,
|
|
1615
|
+
2547177864,
|
|
1616
|
+
162941995,
|
|
1617
|
+
2125561021,
|
|
1618
|
+
3887607047,
|
|
1619
|
+
2428444049,
|
|
1620
|
+
498536548,
|
|
1621
|
+
1789927666,
|
|
1622
|
+
4089016648,
|
|
1623
|
+
2227061214,
|
|
1624
|
+
450548861,
|
|
1625
|
+
1843258603,
|
|
1626
|
+
4107580753,
|
|
1627
|
+
2211677639,
|
|
1628
|
+
325883990,
|
|
1629
|
+
1684777152,
|
|
1630
|
+
4251122042,
|
|
1631
|
+
2321926636,
|
|
1632
|
+
335633487,
|
|
1633
|
+
1661365465,
|
|
1634
|
+
4195302755,
|
|
1635
|
+
2366115317,
|
|
1636
|
+
997073096,
|
|
1637
|
+
1281953886,
|
|
1638
|
+
3579855332,
|
|
1639
|
+
2724688242,
|
|
1640
|
+
1006888145,
|
|
1641
|
+
1258607687,
|
|
1642
|
+
3524101629,
|
|
1643
|
+
2768942443,
|
|
1644
|
+
901097722,
|
|
1645
|
+
1119000684,
|
|
1646
|
+
3686517206,
|
|
1647
|
+
2898065728,
|
|
1648
|
+
853044451,
|
|
1649
|
+
1172266101,
|
|
1650
|
+
3705015759,
|
|
1651
|
+
2882616665,
|
|
1652
|
+
651767980,
|
|
1653
|
+
1373503546,
|
|
1654
|
+
3369554304,
|
|
1655
|
+
3218104598,
|
|
1656
|
+
565507253,
|
|
1657
|
+
1454621731,
|
|
1658
|
+
3485111705,
|
|
1659
|
+
3099436303,
|
|
1660
|
+
671266974,
|
|
1661
|
+
1594198024,
|
|
1662
|
+
3322730930,
|
|
1663
|
+
2970347812,
|
|
1664
|
+
795835527,
|
|
1665
|
+
1483230225,
|
|
1666
|
+
3244367275,
|
|
1667
|
+
3060149565,
|
|
1668
|
+
1994146192,
|
|
1669
|
+
31158534,
|
|
1670
|
+
2563907772,
|
|
1671
|
+
4023717930,
|
|
1672
|
+
1907459465,
|
|
1673
|
+
112637215,
|
|
1674
|
+
2680153253,
|
|
1675
|
+
3904427059,
|
|
1676
|
+
2013776290,
|
|
1677
|
+
251722036,
|
|
1678
|
+
2517215374,
|
|
1679
|
+
3775830040,
|
|
1680
|
+
2137656763,
|
|
1681
|
+
141376813,
|
|
1682
|
+
2439277719,
|
|
1683
|
+
3865271297,
|
|
1684
|
+
1802195444,
|
|
1685
|
+
476864866,
|
|
1686
|
+
2238001368,
|
|
1687
|
+
4066508878,
|
|
1688
|
+
1812370925,
|
|
1689
|
+
453092731,
|
|
1690
|
+
2181625025,
|
|
1691
|
+
4111451223,
|
|
1692
|
+
1706088902,
|
|
1693
|
+
314042704,
|
|
1694
|
+
2344532202,
|
|
1695
|
+
4240017532,
|
|
1696
|
+
1658658271,
|
|
1697
|
+
366619977,
|
|
1698
|
+
2362670323,
|
|
1699
|
+
4224994405,
|
|
1700
|
+
1303535960,
|
|
1701
|
+
984961486,
|
|
1702
|
+
2747007092,
|
|
1703
|
+
3569037538,
|
|
1704
|
+
1256170817,
|
|
1705
|
+
1037604311,
|
|
1706
|
+
2765210733,
|
|
1707
|
+
3554079995,
|
|
1708
|
+
1131014506,
|
|
1709
|
+
879679996,
|
|
1710
|
+
2909243462,
|
|
1711
|
+
3663771856,
|
|
1712
|
+
1141124467,
|
|
1713
|
+
855842277,
|
|
1714
|
+
2852801631,
|
|
1715
|
+
3708648649,
|
|
1716
|
+
1342533948,
|
|
1717
|
+
654459306,
|
|
1718
|
+
3188396048,
|
|
1719
|
+
3373015174,
|
|
1720
|
+
1466479909,
|
|
1721
|
+
544179635,
|
|
1722
|
+
3110523913,
|
|
1723
|
+
3462522015,
|
|
1724
|
+
1591671054,
|
|
1725
|
+
702138776,
|
|
1726
|
+
2966460450,
|
|
1727
|
+
3352799412,
|
|
1728
|
+
1504918807,
|
|
1729
|
+
783551873,
|
|
1730
|
+
3082640443,
|
|
1731
|
+
3233442989,
|
|
1732
|
+
3988292384,
|
|
1733
|
+
2596254646,
|
|
1734
|
+
62317068,
|
|
1735
|
+
1957810842,
|
|
1736
|
+
3939845945,
|
|
1737
|
+
2647816111,
|
|
1738
|
+
81470997,
|
|
1739
|
+
1943803523,
|
|
1740
|
+
3814918930,
|
|
1741
|
+
2489596804,
|
|
1742
|
+
225274430,
|
|
1743
|
+
2053790376,
|
|
1744
|
+
3826175755,
|
|
1745
|
+
2466906013,
|
|
1746
|
+
167816743,
|
|
1747
|
+
2097651377,
|
|
1748
|
+
4027552580,
|
|
1749
|
+
2265490386,
|
|
1750
|
+
503444072,
|
|
1751
|
+
1762050814,
|
|
1752
|
+
4150417245,
|
|
1753
|
+
2154129355,
|
|
1754
|
+
426522225,
|
|
1755
|
+
1852507879,
|
|
1756
|
+
4275313526,
|
|
1757
|
+
2312317920,
|
|
1758
|
+
282753626,
|
|
1759
|
+
1742555852,
|
|
1760
|
+
4189708143,
|
|
1761
|
+
2394877945,
|
|
1762
|
+
397917763,
|
|
1763
|
+
1622183637,
|
|
1764
|
+
3604390888,
|
|
1765
|
+
2714866558,
|
|
1766
|
+
953729732,
|
|
1767
|
+
1340076626,
|
|
1768
|
+
3518719985,
|
|
1769
|
+
2797360999,
|
|
1770
|
+
1068828381,
|
|
1771
|
+
1219638859,
|
|
1772
|
+
3624741850,
|
|
1773
|
+
2936675148,
|
|
1774
|
+
906185462,
|
|
1775
|
+
1090812512,
|
|
1776
|
+
3747672003,
|
|
1777
|
+
2825379669,
|
|
1778
|
+
829329135,
|
|
1779
|
+
1181335161,
|
|
1780
|
+
3412177804,
|
|
1781
|
+
3160834842,
|
|
1782
|
+
628085408,
|
|
1783
|
+
1382605366,
|
|
1784
|
+
3423369109,
|
|
1785
|
+
3138078467,
|
|
1786
|
+
570562233,
|
|
1787
|
+
1426400815,
|
|
1788
|
+
3317316542,
|
|
1789
|
+
2998733608,
|
|
1790
|
+
733239954,
|
|
1791
|
+
1555261956,
|
|
1792
|
+
3268935591,
|
|
1793
|
+
3050360625,
|
|
1794
|
+
752459403,
|
|
1795
|
+
1541320221,
|
|
1796
|
+
2607071920,
|
|
1797
|
+
3965973030,
|
|
1798
|
+
1969922972,
|
|
1799
|
+
40735498,
|
|
1800
|
+
2617837225,
|
|
1801
|
+
3943577151,
|
|
1802
|
+
1913087877,
|
|
1803
|
+
83908371,
|
|
1804
|
+
2512341634,
|
|
1805
|
+
3803740692,
|
|
1806
|
+
2075208622,
|
|
1807
|
+
213261112,
|
|
1808
|
+
2463272603,
|
|
1809
|
+
3855990285,
|
|
1810
|
+
2094854071,
|
|
1811
|
+
198958881,
|
|
1812
|
+
2262029012,
|
|
1813
|
+
4057260610,
|
|
1814
|
+
1759359992,
|
|
1815
|
+
534414190,
|
|
1816
|
+
2176718541,
|
|
1817
|
+
4139329115,
|
|
1818
|
+
1873836001,
|
|
1819
|
+
414664567,
|
|
1820
|
+
2282248934,
|
|
1821
|
+
4279200368,
|
|
1822
|
+
1711684554,
|
|
1823
|
+
285281116,
|
|
1824
|
+
2405801727,
|
|
1825
|
+
4167216745,
|
|
1826
|
+
1634467795,
|
|
1827
|
+
376229701,
|
|
1828
|
+
2685067896,
|
|
1829
|
+
3608007406,
|
|
1830
|
+
1308918612,
|
|
1831
|
+
956543938,
|
|
1832
|
+
2808555105,
|
|
1833
|
+
3495958263,
|
|
1834
|
+
1231636301,
|
|
1835
|
+
1047427035,
|
|
1836
|
+
2932959818,
|
|
1837
|
+
3654703836,
|
|
1838
|
+
1088359270,
|
|
1839
|
+
936918e3,
|
|
1840
|
+
2847714899,
|
|
1841
|
+
3736837829,
|
|
1842
|
+
1202900863,
|
|
1843
|
+
817233897,
|
|
1844
|
+
3183342108,
|
|
1845
|
+
3401237130,
|
|
1846
|
+
1404277552,
|
|
1847
|
+
615818150,
|
|
1848
|
+
3134207493,
|
|
1849
|
+
3453421203,
|
|
1850
|
+
1423857449,
|
|
1851
|
+
601450431,
|
|
1852
|
+
3009837614,
|
|
1853
|
+
3294710456,
|
|
1854
|
+
1567103746,
|
|
1855
|
+
711928724,
|
|
1856
|
+
3020668471,
|
|
1857
|
+
3272380065,
|
|
1858
|
+
1510334235,
|
|
1859
|
+
755167117
|
|
1860
|
+
]);
|
|
1861
|
+
function crc32(buf) {
|
|
1862
|
+
let crc = -1;
|
|
1863
|
+
for (let x of buf) {
|
|
1864
|
+
crc = CRC_TABLE[(crc ^ x) & 255] ^ crc >>> 8;
|
|
1865
|
+
}
|
|
1866
|
+
return (crc ^ -1) >>> 0;
|
|
1867
|
+
}
|
|
1868
|
+
module.exports = crc32;
|
|
1869
|
+
}
|
|
1870
|
+
});
|
|
1871
|
+
|
|
1872
|
+
// ../../packages/node-runtime/node_modules/yauzl/index.js
|
|
1873
|
+
var require_yauzl = __commonJS({
|
|
1874
|
+
"../../packages/node-runtime/node_modules/yauzl/index.js"(exports) {
|
|
1875
|
+
"use strict";
|
|
1876
|
+
var fs29 = __require("fs");
|
|
1877
|
+
var zlib = __require("zlib");
|
|
1878
|
+
var fd_slicer = require_fd_slicer();
|
|
1879
|
+
var util = __require("util");
|
|
1880
|
+
var EventEmitter = __require("events").EventEmitter;
|
|
1881
|
+
var Transform = __require("stream").Transform;
|
|
1882
|
+
var PassThrough = __require("stream").PassThrough;
|
|
1883
|
+
var Writable = __require("stream").Writable;
|
|
1884
|
+
var crc32 = typeof zlib.crc32 === "function" ? zlib.crc32 : require_crc32();
|
|
1885
|
+
exports.open = open;
|
|
1886
|
+
exports.fromFd = fromFd;
|
|
1887
|
+
exports.fromBuffer = fromBuffer;
|
|
1888
|
+
exports.fromRandomAccessReader = fromRandomAccessReader;
|
|
1889
|
+
exports.openPromise = openPromise2;
|
|
1890
|
+
exports.fromFdPromise = fromFdPromise;
|
|
1891
|
+
exports.fromBufferPromise = fromBufferPromise;
|
|
1892
|
+
exports.fromRandomAccessReaderPromise = fromRandomAccessReaderPromise;
|
|
1893
|
+
exports.dosDateTimeToDate = dosDateTimeToDate;
|
|
1894
|
+
exports.getFileNameLowLevel = getFileNameLowLevel;
|
|
1895
|
+
exports.validateFileName = validateFileName;
|
|
1896
|
+
exports.parseExtraFields = parseExtraFields;
|
|
1897
|
+
exports.ZipFile = ZipFile;
|
|
1898
|
+
exports.Entry = Entry;
|
|
1899
|
+
exports.LocalFileHeader = LocalFileHeader;
|
|
1900
|
+
exports.RandomAccessReader = RandomAccessReader;
|
|
1901
|
+
function openPromise2(path24, options2) {
|
|
1902
|
+
return new Promise((resolve3, reject) => {
|
|
1903
|
+
open(path24, { ...options2, lazyEntries: true }, function(err, zipfile) {
|
|
1904
|
+
if (err) return reject(err);
|
|
1905
|
+
resolve3(zipfile);
|
|
1906
|
+
});
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
function fromFdPromise(fd, options2) {
|
|
1910
|
+
return new Promise((resolve3, reject) => {
|
|
1911
|
+
fromFd(fd, { ...options2, lazyEntries: true }, function(err, zipfile) {
|
|
1912
|
+
if (err) return reject(err);
|
|
1913
|
+
resolve3(zipfile);
|
|
1914
|
+
});
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
function fromBufferPromise(buffer, options2) {
|
|
1918
|
+
return new Promise((resolve3, reject) => {
|
|
1919
|
+
fromBuffer(buffer, { ...options2, lazyEntries: true }, function(err, zipfile) {
|
|
1920
|
+
if (err) return reject(err);
|
|
1921
|
+
resolve3(zipfile);
|
|
1922
|
+
});
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
function fromRandomAccessReaderPromise(reader, totalSize, options2) {
|
|
1926
|
+
return new Promise((resolve3, reject) => {
|
|
1927
|
+
fromRandomAccessReader(reader, totalSize, { ...options2, lazyEntries: true }, function(err, zipfile) {
|
|
1928
|
+
if (err) return reject(err);
|
|
1929
|
+
resolve3(zipfile);
|
|
1930
|
+
});
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
function open(path24, options2, callback) {
|
|
1934
|
+
if (typeof options2 === "function") {
|
|
1935
|
+
callback = options2;
|
|
1936
|
+
options2 = null;
|
|
1937
|
+
}
|
|
1938
|
+
if (options2 == null) options2 = {};
|
|
1939
|
+
if (options2.autoClose == null) options2.autoClose = true;
|
|
1940
|
+
if (options2.lazyEntries == null) options2.lazyEntries = false;
|
|
1941
|
+
if (options2.decodeStrings == null) options2.decodeStrings = true;
|
|
1942
|
+
if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
|
|
1943
|
+
if (options2.strictFileNames == null) options2.strictFileNames = false;
|
|
1944
|
+
if (callback == null) callback = defaultCallback;
|
|
1945
|
+
fs29.open(path24, "r", function(err, fd) {
|
|
1946
|
+
if (err) return callback(err);
|
|
1947
|
+
fromFd(fd, options2, function(err2, zipfile) {
|
|
1948
|
+
if (err2) fs29.close(fd, defaultCallback);
|
|
1949
|
+
callback(err2, zipfile);
|
|
1950
|
+
});
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
function fromFd(fd, options2, callback) {
|
|
1954
|
+
if (typeof options2 === "function") {
|
|
1955
|
+
callback = options2;
|
|
1956
|
+
options2 = null;
|
|
1957
|
+
}
|
|
1958
|
+
if (options2 == null) options2 = {};
|
|
1959
|
+
if (options2.autoClose == null) options2.autoClose = false;
|
|
1960
|
+
if (options2.lazyEntries == null) options2.lazyEntries = false;
|
|
1961
|
+
if (options2.decodeStrings == null) options2.decodeStrings = true;
|
|
1962
|
+
if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
|
|
1963
|
+
if (options2.strictFileNames == null) options2.strictFileNames = false;
|
|
1964
|
+
if (callback == null) callback = defaultCallback;
|
|
1965
|
+
fs29.fstat(fd, function(err, stats) {
|
|
1966
|
+
if (err) return callback(err);
|
|
1967
|
+
var reader = new fd_slicer.FdSlicer(fd);
|
|
1968
|
+
fromRandomAccessReader(reader, stats.size, options2, callback);
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
function fromBuffer(buffer, options2, callback) {
|
|
1972
|
+
if (typeof options2 === "function") {
|
|
1973
|
+
callback = options2;
|
|
1974
|
+
options2 = null;
|
|
1975
|
+
}
|
|
1976
|
+
if (options2 == null) options2 = {};
|
|
1977
|
+
options2.autoClose = false;
|
|
1978
|
+
if (options2.lazyEntries == null) options2.lazyEntries = false;
|
|
1979
|
+
if (options2.decodeStrings == null) options2.decodeStrings = true;
|
|
1980
|
+
if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
|
|
1981
|
+
if (options2.strictFileNames == null) options2.strictFileNames = false;
|
|
1982
|
+
var reader = new fd_slicer.BufferSlicer(buffer);
|
|
1983
|
+
fromRandomAccessReader(reader, buffer.length, options2, callback);
|
|
1984
|
+
}
|
|
1985
|
+
function fromRandomAccessReader(reader, totalSize, options2, callback) {
|
|
1986
|
+
if (typeof options2 === "function") {
|
|
1987
|
+
callback = options2;
|
|
1988
|
+
options2 = null;
|
|
1989
|
+
}
|
|
1990
|
+
if (options2 == null) options2 = {};
|
|
1991
|
+
if (options2.autoClose == null) options2.autoClose = true;
|
|
1992
|
+
if (options2.lazyEntries == null) options2.lazyEntries = false;
|
|
1993
|
+
if (options2.decodeStrings == null) options2.decodeStrings = true;
|
|
1994
|
+
var decodeStrings = !!options2.decodeStrings;
|
|
1995
|
+
if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
|
|
1996
|
+
if (options2.strictFileNames == null) options2.strictFileNames = false;
|
|
1997
|
+
if (callback == null) callback = defaultCallback;
|
|
1998
|
+
if (typeof totalSize !== "number") throw new Error("expected totalSize parameter to be a number");
|
|
1999
|
+
if (totalSize > Number.MAX_SAFE_INTEGER) {
|
|
2000
|
+
throw new Error("zip file too large. only file sizes up to 2^52 are supported due to JavaScript's Number type being an IEEE 754 double.");
|
|
2001
|
+
}
|
|
2002
|
+
reader.ref();
|
|
2003
|
+
var eocdrWithoutCommentSize = 22;
|
|
2004
|
+
var zip64EocdlSize = 20;
|
|
2005
|
+
var maxCommentSize = 65535;
|
|
2006
|
+
var bufferSize = Math.min(zip64EocdlSize + eocdrWithoutCommentSize + maxCommentSize, totalSize);
|
|
2007
|
+
var buffer = newBuffer(bufferSize);
|
|
2008
|
+
var bufferReadStart = totalSize - buffer.length;
|
|
2009
|
+
readAndAssertNoEof(reader, buffer, 0, bufferSize, bufferReadStart, function(err) {
|
|
2010
|
+
if (err) return callback(err);
|
|
2011
|
+
for (var i = bufferSize - eocdrWithoutCommentSize; i >= 0; i -= 1) {
|
|
2012
|
+
if (buffer.readUInt32LE(i) !== 101010256) continue;
|
|
2013
|
+
var eocdrBuffer = buffer.subarray(i);
|
|
2014
|
+
var diskNumber = eocdrBuffer.readUInt16LE(4);
|
|
2015
|
+
var entryCount = eocdrBuffer.readUInt16LE(10);
|
|
2016
|
+
var centralDirectoryOffset = eocdrBuffer.readUInt32LE(16);
|
|
2017
|
+
var commentLength = eocdrBuffer.readUInt16LE(20);
|
|
2018
|
+
var expectedCommentLength = eocdrBuffer.length - eocdrWithoutCommentSize;
|
|
2019
|
+
if (commentLength !== expectedCommentLength) {
|
|
2020
|
+
return callback(new Error("Invalid comment length. Expected: " + expectedCommentLength + ". Found: " + commentLength + ". Are there extra bytes at the end of the file? Or is the end of central dir signature `PK\u263A\u263B` in the comment?"));
|
|
2021
|
+
}
|
|
2022
|
+
var comment = decodeStrings ? decodeBuffer(eocdrBuffer.subarray(22), false) : eocdrBuffer.subarray(22);
|
|
2023
|
+
if (i - zip64EocdlSize >= 0 && buffer.readUInt32LE(i - zip64EocdlSize) === 117853008) {
|
|
2024
|
+
var zip64EocdlBuffer = buffer.subarray(i - zip64EocdlSize, i - zip64EocdlSize + zip64EocdlSize);
|
|
2025
|
+
var zip64EocdrOffset = readUInt64LE(zip64EocdlBuffer, 8);
|
|
2026
|
+
var zip64EocdrBuffer = newBuffer(56);
|
|
2027
|
+
return readAndAssertNoEof(reader, zip64EocdrBuffer, 0, zip64EocdrBuffer.length, zip64EocdrOffset, function(err2) {
|
|
2028
|
+
if (err2) return callback(err2);
|
|
2029
|
+
if (zip64EocdrBuffer.readUInt32LE(0) !== 101075792) {
|
|
2030
|
+
return callback(new Error("invalid zip64 end of central directory record signature"));
|
|
2031
|
+
}
|
|
2032
|
+
diskNumber = zip64EocdrBuffer.readUInt32LE(16);
|
|
2033
|
+
if (diskNumber !== 0) {
|
|
2034
|
+
return callback(new Error("multi-disk zip files are not supported: found disk number: " + diskNumber));
|
|
2035
|
+
}
|
|
2036
|
+
entryCount = readUInt64LE(zip64EocdrBuffer, 32);
|
|
2037
|
+
centralDirectoryOffset = readUInt64LE(zip64EocdrBuffer, 48);
|
|
2038
|
+
return callback(null, new ZipFile(reader, centralDirectoryOffset, totalSize, entryCount, comment, options2.autoClose, options2.lazyEntries, decodeStrings, options2.validateEntrySizes, options2.strictFileNames));
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
if (diskNumber !== 0) {
|
|
2042
|
+
return callback(new Error("multi-disk zip files are not supported: found disk number: " + diskNumber));
|
|
2043
|
+
}
|
|
2044
|
+
return callback(null, new ZipFile(reader, centralDirectoryOffset, totalSize, entryCount, comment, options2.autoClose, options2.lazyEntries, decodeStrings, options2.validateEntrySizes, options2.strictFileNames));
|
|
2045
|
+
}
|
|
2046
|
+
callback(new Error("End of central directory record signature not found. Either not a zip file, or file is truncated."));
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
util.inherits(ZipFile, EventEmitter);
|
|
2050
|
+
function ZipFile(reader, centralDirectoryOffset, fileSize, entryCount, comment, autoClose, lazyEntries, decodeStrings, validateEntrySizes, strictFileNames) {
|
|
2051
|
+
var self = this;
|
|
2052
|
+
EventEmitter.call(self);
|
|
2053
|
+
self.reader = reader;
|
|
2054
|
+
self.reader.on("error", function(err) {
|
|
2055
|
+
emitError(self, err);
|
|
2056
|
+
});
|
|
2057
|
+
self.reader.once("close", function() {
|
|
2058
|
+
self.emit("close");
|
|
2059
|
+
});
|
|
2060
|
+
self.readEntryCursor = centralDirectoryOffset;
|
|
2061
|
+
self.fileSize = fileSize;
|
|
2062
|
+
self.entryCount = entryCount;
|
|
2063
|
+
self.comment = comment;
|
|
2064
|
+
self.entriesRead = 0;
|
|
2065
|
+
self.autoClose = !!autoClose;
|
|
2066
|
+
self.lazyEntries = !!lazyEntries;
|
|
2067
|
+
self.decodeStrings = !!decodeStrings;
|
|
2068
|
+
self.validateEntrySizes = !!validateEntrySizes;
|
|
2069
|
+
self.strictFileNames = !!strictFileNames;
|
|
2070
|
+
self.isOpen = true;
|
|
2071
|
+
self.emittedError = false;
|
|
2072
|
+
self.hasEachEntryBeenCalled = false;
|
|
2073
|
+
if (!self.lazyEntries) self._readEntry();
|
|
2074
|
+
}
|
|
2075
|
+
ZipFile.prototype.close = function() {
|
|
2076
|
+
if (!this.isOpen) return;
|
|
2077
|
+
this.isOpen = false;
|
|
2078
|
+
this.reader.unref();
|
|
2079
|
+
};
|
|
2080
|
+
function emitErrorAndAutoClose(self, err) {
|
|
2081
|
+
if (self.autoClose) self.close();
|
|
2082
|
+
emitError(self, err);
|
|
2083
|
+
}
|
|
2084
|
+
function emitError(self, err) {
|
|
2085
|
+
if (self.emittedError) return;
|
|
2086
|
+
self.emittedError = true;
|
|
2087
|
+
self.emit("error", err);
|
|
2088
|
+
}
|
|
2089
|
+
ZipFile.prototype.readEntry = function() {
|
|
2090
|
+
if (!this.lazyEntries) throw new Error("readEntry() called without lazyEntries:true");
|
|
2091
|
+
this._readEntry();
|
|
2092
|
+
};
|
|
2093
|
+
ZipFile.prototype._readEntry = function() {
|
|
2094
|
+
var self = this;
|
|
2095
|
+
if (self.entryCount === self.entriesRead) {
|
|
2096
|
+
setImmediate(function() {
|
|
2097
|
+
if (self.autoClose) self.close();
|
|
2098
|
+
if (self.emittedError) return;
|
|
2099
|
+
self.emit("end");
|
|
2100
|
+
});
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
2103
|
+
if (self.emittedError) return;
|
|
2104
|
+
var buffer = newBuffer(46);
|
|
2105
|
+
readAndAssertNoEof(self.reader, buffer, 0, buffer.length, self.readEntryCursor, function(err) {
|
|
2106
|
+
if (err) return emitErrorAndAutoClose(self, err);
|
|
2107
|
+
if (self.emittedError) return;
|
|
2108
|
+
var entry = new Entry();
|
|
2109
|
+
var signature = buffer.readUInt32LE(0);
|
|
2110
|
+
if (signature !== 33639248) return emitErrorAndAutoClose(self, new Error("invalid central directory file header signature: 0x" + signature.toString(16)));
|
|
2111
|
+
entry.versionMadeBy = buffer.readUInt16LE(4);
|
|
2112
|
+
entry.versionNeededToExtract = buffer.readUInt16LE(6);
|
|
2113
|
+
entry.generalPurposeBitFlag = buffer.readUInt16LE(8);
|
|
2114
|
+
entry.compressionMethod = buffer.readUInt16LE(10);
|
|
2115
|
+
entry.lastModFileTime = buffer.readUInt16LE(12);
|
|
2116
|
+
entry.lastModFileDate = buffer.readUInt16LE(14);
|
|
2117
|
+
entry.crc32 = buffer.readUInt32LE(16);
|
|
2118
|
+
entry.compressedSize = buffer.readUInt32LE(20);
|
|
2119
|
+
entry.uncompressedSize = buffer.readUInt32LE(24);
|
|
2120
|
+
entry.fileNameLength = buffer.readUInt16LE(28);
|
|
2121
|
+
entry.extraFieldLength = buffer.readUInt16LE(30);
|
|
2122
|
+
entry.fileCommentLength = buffer.readUInt16LE(32);
|
|
2123
|
+
entry.internalFileAttributes = buffer.readUInt16LE(36);
|
|
2124
|
+
entry.externalFileAttributes = buffer.readUInt32LE(38);
|
|
2125
|
+
entry.relativeOffsetOfLocalHeader = buffer.readUInt32LE(42);
|
|
2126
|
+
if (entry.generalPurposeBitFlag & 64) return emitErrorAndAutoClose(self, new Error("strong encryption is not supported"));
|
|
2127
|
+
self.readEntryCursor += 46;
|
|
2128
|
+
buffer = newBuffer(entry.fileNameLength + entry.extraFieldLength + entry.fileCommentLength);
|
|
2129
|
+
readAndAssertNoEof(self.reader, buffer, 0, buffer.length, self.readEntryCursor, function(err2) {
|
|
2130
|
+
if (err2) return emitErrorAndAutoClose(self, err2);
|
|
2131
|
+
if (self.emittedError) return;
|
|
2132
|
+
entry.fileNameRaw = buffer.subarray(0, entry.fileNameLength);
|
|
2133
|
+
var fileCommentStart = entry.fileNameLength + entry.extraFieldLength;
|
|
2134
|
+
entry.extraFieldRaw = buffer.subarray(entry.fileNameLength, fileCommentStart);
|
|
2135
|
+
entry.fileCommentRaw = buffer.subarray(fileCommentStart, fileCommentStart + entry.fileCommentLength);
|
|
2136
|
+
try {
|
|
2137
|
+
entry.extraFields = parseExtraFields(entry.extraFieldRaw);
|
|
2138
|
+
} catch (err3) {
|
|
2139
|
+
return emitErrorAndAutoClose(self, err3);
|
|
2140
|
+
}
|
|
2141
|
+
if (self.decodeStrings) {
|
|
2142
|
+
var isUtf8 = (entry.generalPurposeBitFlag & 2048) !== 0;
|
|
2143
|
+
entry.fileComment = decodeBuffer(entry.fileCommentRaw, isUtf8);
|
|
2144
|
+
entry.fileName = getFileNameLowLevel(entry.generalPurposeBitFlag, entry.fileNameRaw, entry.extraFields, self.strictFileNames);
|
|
2145
|
+
var errorMessage = validateFileName(entry.fileName);
|
|
2146
|
+
if (errorMessage != null) return emitErrorAndAutoClose(self, new Error(errorMessage));
|
|
2147
|
+
} else {
|
|
2148
|
+
entry.fileComment = entry.fileCommentRaw;
|
|
2149
|
+
entry.fileName = entry.fileNameRaw;
|
|
2150
|
+
}
|
|
2151
|
+
entry.comment = entry.fileComment;
|
|
2152
|
+
self.readEntryCursor += buffer.length;
|
|
2153
|
+
self.entriesRead += 1;
|
|
2154
|
+
for (var i = 0; i < entry.extraFields.length; i++) {
|
|
2155
|
+
var extraField = entry.extraFields[i];
|
|
2156
|
+
if (extraField.id !== 1) continue;
|
|
2157
|
+
var zip64EiefBuffer = extraField.data;
|
|
2158
|
+
var index = 0;
|
|
2159
|
+
if (entry.uncompressedSize === 4294967295) {
|
|
2160
|
+
if (index + 8 > zip64EiefBuffer.length) {
|
|
2161
|
+
return emitErrorAndAutoClose(self, new Error("zip64 extended information extra field does not include uncompressed size"));
|
|
2162
|
+
}
|
|
2163
|
+
entry.uncompressedSize = readUInt64LE(zip64EiefBuffer, index);
|
|
2164
|
+
index += 8;
|
|
2165
|
+
}
|
|
2166
|
+
if (entry.compressedSize === 4294967295) {
|
|
2167
|
+
if (index + 8 > zip64EiefBuffer.length) {
|
|
2168
|
+
return emitErrorAndAutoClose(self, new Error("zip64 extended information extra field does not include compressed size"));
|
|
2169
|
+
}
|
|
2170
|
+
entry.compressedSize = readUInt64LE(zip64EiefBuffer, index);
|
|
2171
|
+
index += 8;
|
|
2172
|
+
}
|
|
2173
|
+
if (entry.relativeOffsetOfLocalHeader === 4294967295) {
|
|
2174
|
+
if (index + 8 > zip64EiefBuffer.length) {
|
|
2175
|
+
return emitErrorAndAutoClose(self, new Error("zip64 extended information extra field does not include relative header offset"));
|
|
2176
|
+
}
|
|
2177
|
+
entry.relativeOffsetOfLocalHeader = readUInt64LE(zip64EiefBuffer, index);
|
|
2178
|
+
index += 8;
|
|
2179
|
+
}
|
|
2180
|
+
break;
|
|
2181
|
+
}
|
|
2182
|
+
if (self.validateEntrySizes && entry.compressionMethod === 0) {
|
|
2183
|
+
var expectedCompressedSize = entry.uncompressedSize;
|
|
2184
|
+
if (entry.isEncrypted()) {
|
|
2185
|
+
expectedCompressedSize += 12;
|
|
2186
|
+
}
|
|
2187
|
+
if (entry.compressedSize !== expectedCompressedSize) {
|
|
2188
|
+
var msg = "compressed/uncompressed size mismatch for stored file: " + entry.compressedSize + " != " + entry.uncompressedSize;
|
|
2189
|
+
return emitErrorAndAutoClose(self, new Error(msg));
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
self.emit("entry", entry);
|
|
2193
|
+
if (!self.lazyEntries) self._readEntry();
|
|
2194
|
+
});
|
|
2195
|
+
});
|
|
2196
|
+
};
|
|
2197
|
+
ZipFile.prototype.eachEntry = function() {
|
|
2198
|
+
const self = this;
|
|
2199
|
+
if (!self.lazyEntries) throw new Error("eachEntry() requires lazyEntries: true");
|
|
2200
|
+
if (self.hasEachEntryBeenCalled) throw new Error("eachEntry() must only be called once per ZipFile");
|
|
2201
|
+
self.hasEachEntryBeenCalled = true;
|
|
2202
|
+
let pendingResolveReject = null;
|
|
2203
|
+
self.on("entry", onEntry);
|
|
2204
|
+
self.on("end", onEnd);
|
|
2205
|
+
self.on("error", onError);
|
|
2206
|
+
function cleanup() {
|
|
2207
|
+
self.removeListener("entry", onEntry);
|
|
2208
|
+
self.removeListener("end", onEnd);
|
|
2209
|
+
self.removeListener("error", onError);
|
|
2210
|
+
if (self.autoClose) self.close();
|
|
2211
|
+
}
|
|
2212
|
+
function onEntry(entry) {
|
|
2213
|
+
let { resolve: resolve3 } = pendingResolveReject;
|
|
2214
|
+
pendingResolveReject = null;
|
|
2215
|
+
resolve3({ value: entry });
|
|
2216
|
+
}
|
|
2217
|
+
function onEnd() {
|
|
2218
|
+
let { resolve: resolve3 } = pendingResolveReject;
|
|
2219
|
+
pendingResolveReject = null;
|
|
2220
|
+
cleanup();
|
|
2221
|
+
resolve3({ done: true });
|
|
2222
|
+
}
|
|
2223
|
+
function onError(err) {
|
|
2224
|
+
let { reject } = pendingResolveReject;
|
|
2225
|
+
pendingResolveReject = null;
|
|
2226
|
+
cleanup();
|
|
2227
|
+
reject(err);
|
|
2228
|
+
}
|
|
2229
|
+
return {
|
|
2230
|
+
[Symbol.asyncIterator]() {
|
|
2231
|
+
return this;
|
|
2232
|
+
},
|
|
2233
|
+
next() {
|
|
2234
|
+
const promise = new Promise((resolve3, reject) => {
|
|
2235
|
+
if (pendingResolveReject != null) throw new Error("next() called before previous Promise was resolved.");
|
|
2236
|
+
pendingResolveReject = { resolve: resolve3, reject };
|
|
2237
|
+
});
|
|
2238
|
+
self.readEntry();
|
|
2239
|
+
return promise;
|
|
2240
|
+
},
|
|
2241
|
+
return(value) {
|
|
2242
|
+
cleanup();
|
|
2243
|
+
return Promise.resolve({ done: true, value });
|
|
2244
|
+
},
|
|
2245
|
+
throw(value) {
|
|
2246
|
+
cleanup();
|
|
2247
|
+
return Promise.reject(value);
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
};
|
|
2251
|
+
ZipFile.prototype.openReadStream = function(entry, options2, callback) {
|
|
2252
|
+
var self = this;
|
|
2253
|
+
var relativeStart = 0;
|
|
2254
|
+
var relativeEnd = entry.compressedSize;
|
|
2255
|
+
if (callback == null) {
|
|
2256
|
+
callback = options2;
|
|
2257
|
+
options2 = null;
|
|
2258
|
+
}
|
|
2259
|
+
if (options2 == null) {
|
|
2260
|
+
options2 = {};
|
|
2261
|
+
} else {
|
|
2262
|
+
if (options2.decodeFileData === false) {
|
|
2263
|
+
if (options2.decrypt != null) {
|
|
2264
|
+
throw new Error("cannot use options.decrypt when options.decodeFileData === false");
|
|
2265
|
+
}
|
|
2266
|
+
if (options2.decompress != null) {
|
|
2267
|
+
throw new Error("cannot use options.decompress when options.decodeFileData === false");
|
|
2268
|
+
}
|
|
2269
|
+
} else {
|
|
2270
|
+
if (options2.decrypt != null) {
|
|
2271
|
+
if (!entry.isEncrypted()) {
|
|
2272
|
+
throw new Error("options.decrypt can only be specified for encrypted entries. See also option decodeFileData.");
|
|
2273
|
+
}
|
|
2274
|
+
if (options2.decrypt !== false) throw new Error("invalid options.decrypt value: " + options2.decrypt);
|
|
2275
|
+
if (entry.isCompressed()) {
|
|
2276
|
+
if (options2.decompress !== false) throw new Error("entry is encrypted and compressed, and options.decompress !== false. See also option decodeFileData.");
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
if (options2.decompress != null) {
|
|
2280
|
+
if (!entry.isCompressed()) {
|
|
2281
|
+
throw new Error("options.decompress can only be specified for compressed entries. See also option decodeFileData.");
|
|
2282
|
+
}
|
|
2283
|
+
if (!(options2.decompress === false || options2.decompress === true)) {
|
|
2284
|
+
throw new Error("invalid options.decompress value: " + options2.decompress);
|
|
2285
|
+
}
|
|
2286
|
+
decompress = options2.decompress;
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
if (options2.start != null) {
|
|
2290
|
+
relativeStart = options2.start;
|
|
2291
|
+
if (relativeStart < 0) throw new Error("options.start < 0");
|
|
2292
|
+
if (relativeStart > entry.compressedSize) throw new Error("options.start > entry.compressedSize");
|
|
2293
|
+
}
|
|
2294
|
+
if (options2.end != null) {
|
|
2295
|
+
relativeEnd = options2.end;
|
|
2296
|
+
if (relativeEnd < 0) throw new Error("options.end < 0");
|
|
2297
|
+
if (relativeEnd > entry.compressedSize) throw new Error("options.end > entry.compressedSize");
|
|
2298
|
+
if (relativeEnd < relativeStart) throw new Error("options.end < options.start");
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
var rawMode = options2.decodeFileData === false || // Explicitly requested raw.
|
|
2302
|
+
(entry.compressionMethod === 0 || // Naturally without compression.
|
|
2303
|
+
entry.compressionMethod === 8 && options2.decompress === false) && (!entry.isEncrypted() || // Naturally without encryption.
|
|
2304
|
+
options2.decrypt === false);
|
|
2305
|
+
if (options2.start != null || options2.end != null) {
|
|
2306
|
+
if (!rawMode) throw new Error("start/end range require options.decodeFileData === false for non-trivial encoded entries.");
|
|
2307
|
+
}
|
|
2308
|
+
if (!self.isOpen) return callback(new Error("closed"));
|
|
2309
|
+
if (entry.isEncrypted() && !rawMode) {
|
|
2310
|
+
if (options2.decrypt !== false) return callback(new Error("entry is encrypted, and options.decodeFileData !== false"));
|
|
2311
|
+
}
|
|
2312
|
+
var decompress;
|
|
2313
|
+
if (rawMode) {
|
|
2314
|
+
decompress = false;
|
|
2315
|
+
} else if (entry.compressionMethod === 8) {
|
|
2316
|
+
decompress = options2.decodeFileData !== true;
|
|
2317
|
+
} else {
|
|
2318
|
+
return callback(new Error("unsupported compression method: " + entry.compressionMethod));
|
|
2319
|
+
}
|
|
2320
|
+
self.readLocalFileHeader(entry, { minimal: true }, function(err, localFileHeader) {
|
|
2321
|
+
if (err) return callback(err);
|
|
2322
|
+
self.openReadStreamLowLevel(
|
|
2323
|
+
localFileHeader.fileDataStart,
|
|
2324
|
+
entry.compressedSize,
|
|
2325
|
+
relativeStart,
|
|
2326
|
+
relativeEnd,
|
|
2327
|
+
decompress,
|
|
2328
|
+
entry.uncompressedSize,
|
|
2329
|
+
callback
|
|
2330
|
+
);
|
|
2331
|
+
});
|
|
2332
|
+
};
|
|
2333
|
+
ZipFile.prototype.openReadStreamLowLevel = function(fileDataStart, compressedSize, relativeStart, relativeEnd, decompress, uncompressedSize, callback) {
|
|
2334
|
+
var self = this;
|
|
2335
|
+
var fileDataEnd = fileDataStart + compressedSize;
|
|
2336
|
+
var readStream = self.reader.createReadStream({
|
|
2337
|
+
start: fileDataStart + relativeStart,
|
|
2338
|
+
end: fileDataStart + relativeEnd
|
|
2339
|
+
});
|
|
2340
|
+
var endpointStream = readStream;
|
|
2341
|
+
if (decompress) {
|
|
2342
|
+
var destroyed = false;
|
|
2343
|
+
var inflateFilter = zlib.createInflateRaw();
|
|
2344
|
+
readStream.on("error", function(err) {
|
|
2345
|
+
setImmediate(function() {
|
|
2346
|
+
if (!destroyed) inflateFilter.emit("error", err);
|
|
2347
|
+
});
|
|
2348
|
+
});
|
|
2349
|
+
readStream.pipe(inflateFilter);
|
|
2350
|
+
if (self.validateEntrySizes) {
|
|
2351
|
+
endpointStream = new AssertByteCountStream(uncompressedSize);
|
|
2352
|
+
inflateFilter.on("error", function(err) {
|
|
2353
|
+
setImmediate(function() {
|
|
2354
|
+
if (!destroyed) endpointStream.emit("error", err);
|
|
2355
|
+
});
|
|
2356
|
+
});
|
|
2357
|
+
inflateFilter.pipe(endpointStream);
|
|
2358
|
+
} else {
|
|
2359
|
+
endpointStream = inflateFilter;
|
|
2360
|
+
}
|
|
2361
|
+
installDestroyFn(endpointStream, function() {
|
|
2362
|
+
destroyed = true;
|
|
2363
|
+
if (inflateFilter !== endpointStream) inflateFilter.unpipe(endpointStream);
|
|
2364
|
+
readStream.unpipe(inflateFilter);
|
|
2365
|
+
readStream.destroy();
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
callback(null, endpointStream);
|
|
2369
|
+
};
|
|
2370
|
+
ZipFile.prototype.readLocalFileHeader = function(entry, options2, callback) {
|
|
2371
|
+
var self = this;
|
|
2372
|
+
if (callback == null) {
|
|
2373
|
+
callback = options2;
|
|
2374
|
+
options2 = null;
|
|
2375
|
+
}
|
|
2376
|
+
if (options2 == null) options2 = {};
|
|
2377
|
+
self.reader.ref();
|
|
2378
|
+
var buffer = newBuffer(30);
|
|
2379
|
+
readAndAssertNoEof(self.reader, buffer, 0, buffer.length, entry.relativeOffsetOfLocalHeader, function(err) {
|
|
2380
|
+
try {
|
|
2381
|
+
if (err) return callback(err);
|
|
2382
|
+
var signature = buffer.readUInt32LE(0);
|
|
2383
|
+
if (signature !== 67324752) {
|
|
2384
|
+
return callback(new Error("invalid local file header signature: 0x" + signature.toString(16)));
|
|
2385
|
+
}
|
|
2386
|
+
var fileNameLength = buffer.readUInt16LE(26);
|
|
2387
|
+
var extraFieldLength = buffer.readUInt16LE(28);
|
|
2388
|
+
var fileDataStart = entry.relativeOffsetOfLocalHeader + 30 + fileNameLength + extraFieldLength;
|
|
2389
|
+
if (fileDataStart + entry.compressedSize > self.fileSize) {
|
|
2390
|
+
return callback(new Error("file data overflows file bounds: " + fileDataStart + " + " + entry.compressedSize + " > " + self.fileSize));
|
|
2391
|
+
}
|
|
2392
|
+
if (options2.minimal) {
|
|
2393
|
+
return callback(null, { fileDataStart });
|
|
2394
|
+
}
|
|
2395
|
+
var localFileHeader = new LocalFileHeader();
|
|
2396
|
+
localFileHeader.fileDataStart = fileDataStart;
|
|
2397
|
+
localFileHeader.versionNeededToExtract = buffer.readUInt16LE(4);
|
|
2398
|
+
localFileHeader.generalPurposeBitFlag = buffer.readUInt16LE(6);
|
|
2399
|
+
localFileHeader.compressionMethod = buffer.readUInt16LE(8);
|
|
2400
|
+
localFileHeader.lastModFileTime = buffer.readUInt16LE(10);
|
|
2401
|
+
localFileHeader.lastModFileDate = buffer.readUInt16LE(12);
|
|
2402
|
+
localFileHeader.crc32 = buffer.readUInt32LE(14);
|
|
2403
|
+
localFileHeader.compressedSize = buffer.readUInt32LE(18);
|
|
2404
|
+
localFileHeader.uncompressedSize = buffer.readUInt32LE(22);
|
|
2405
|
+
localFileHeader.fileNameLength = fileNameLength;
|
|
2406
|
+
localFileHeader.extraFieldLength = extraFieldLength;
|
|
2407
|
+
buffer = newBuffer(fileNameLength + extraFieldLength);
|
|
2408
|
+
self.reader.ref();
|
|
2409
|
+
readAndAssertNoEof(self.reader, buffer, 0, buffer.length, entry.relativeOffsetOfLocalHeader + 30, function(err2) {
|
|
2410
|
+
try {
|
|
2411
|
+
if (err2) return callback(err2);
|
|
2412
|
+
localFileHeader.fileName = buffer.subarray(0, fileNameLength);
|
|
2413
|
+
localFileHeader.extraField = buffer.subarray(fileNameLength);
|
|
2414
|
+
return callback(null, localFileHeader);
|
|
2415
|
+
} finally {
|
|
2416
|
+
self.reader.unref();
|
|
2417
|
+
}
|
|
2418
|
+
});
|
|
2419
|
+
} finally {
|
|
2420
|
+
self.reader.unref();
|
|
2421
|
+
}
|
|
2422
|
+
});
|
|
2423
|
+
};
|
|
2424
|
+
ZipFile.prototype.openReadStreamPromise = function(entry, options2) {
|
|
2425
|
+
return new Promise((resolve3, reject) => {
|
|
2426
|
+
this.openReadStream(entry, options2, function(err, readStream) {
|
|
2427
|
+
if (err) return reject(err);
|
|
2428
|
+
resolve3(readStream);
|
|
2429
|
+
});
|
|
2430
|
+
});
|
|
2431
|
+
};
|
|
2432
|
+
ZipFile.prototype.openReadStreamLowLevelPromise = function(fileDataStart, compressedSize, relativeStart, relativeEnd, decompress, uncompressedSize) {
|
|
2433
|
+
return new Promise((resolve3, reject) => {
|
|
2434
|
+
this.openReadStream(fileDataStart, compressedSize, relativeStart, relativeEnd, decompress, uncompressedSize, function(err, readStream) {
|
|
2435
|
+
if (err) return reject(err);
|
|
2436
|
+
resolve3(readStream);
|
|
2437
|
+
});
|
|
2438
|
+
});
|
|
2439
|
+
};
|
|
2440
|
+
ZipFile.prototype.readLocalFileHeaderPromise = function(entry, options2) {
|
|
2441
|
+
return new Promise((resolve3, reject) => {
|
|
2442
|
+
this.readLocalFileHeader(entry, options2, function(err, localFileHeader) {
|
|
2443
|
+
if (err) return reject(err);
|
|
2444
|
+
resolve3(localFileHeader);
|
|
2445
|
+
});
|
|
2446
|
+
});
|
|
2447
|
+
};
|
|
2448
|
+
function Entry() {
|
|
2449
|
+
}
|
|
2450
|
+
Entry.prototype.getLastModDate = function(options2) {
|
|
2451
|
+
if (options2 == null) options2 = {};
|
|
2452
|
+
if (!options2.forceDosFormat) {
|
|
2453
|
+
for (var i = 0; i < this.extraFields.length; i++) {
|
|
2454
|
+
var extraField = this.extraFields[i];
|
|
2455
|
+
if (extraField.id === 21589) {
|
|
2456
|
+
var data = extraField.data;
|
|
2457
|
+
if (data.length < 5) continue;
|
|
2458
|
+
var flags = data[0];
|
|
2459
|
+
var HAS_MTIME = 1;
|
|
2460
|
+
if (!(flags & HAS_MTIME)) continue;
|
|
2461
|
+
var posixTimestamp = data.readInt32LE(1);
|
|
2462
|
+
return new Date(posixTimestamp * 1e3);
|
|
2463
|
+
} else if (extraField.id === 10) {
|
|
2464
|
+
var data = extraField.data;
|
|
2465
|
+
if (data.length !== 32) continue;
|
|
2466
|
+
if (data.readUInt16LE(4) !== 1) continue;
|
|
2467
|
+
if (data.readUInt16LE(6) !== 24) continue;
|
|
2468
|
+
var hundredNanoSecondsSince1601 = data.readUInt32LE(8) + 4294967296 * data.readInt32LE(12);
|
|
2469
|
+
var millisecondsSince1970 = hundredNanoSecondsSince1601 / 1e4 - 116444736e5;
|
|
2470
|
+
return new Date(millisecondsSince1970);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
return dosDateTimeToDate(this.lastModFileDate, this.lastModFileTime, options2.timezone);
|
|
2475
|
+
};
|
|
2476
|
+
Entry.prototype.canDecodeFileData = function() {
|
|
2477
|
+
return !this.isEncrypted() && (this.compressionMethod === 0 || this.compressionMethod === 8);
|
|
2478
|
+
};
|
|
2479
|
+
Entry.prototype.isEncrypted = function() {
|
|
2480
|
+
return (this.generalPurposeBitFlag & 1) !== 0;
|
|
2481
|
+
};
|
|
2482
|
+
Entry.prototype.isCompressed = function() {
|
|
2483
|
+
return this.compressionMethod === 8;
|
|
2484
|
+
};
|
|
2485
|
+
function LocalFileHeader() {
|
|
2486
|
+
}
|
|
2487
|
+
function dosDateTimeToDate(date, time, timezone) {
|
|
2488
|
+
var day = date & 31;
|
|
2489
|
+
var month = (date >> 5 & 15) - 1;
|
|
2490
|
+
var year = (date >> 9 & 127) + 1980;
|
|
2491
|
+
var millisecond = 0;
|
|
2492
|
+
var second = (time & 31) * 2;
|
|
2493
|
+
var minute = time >> 5 & 63;
|
|
2494
|
+
var hour = time >> 11 & 31;
|
|
2495
|
+
if (timezone == null || timezone === "local") {
|
|
2496
|
+
return new Date(year, month, day, hour, minute, second, millisecond);
|
|
2497
|
+
} else if (timezone === "UTC") {
|
|
2498
|
+
return new Date(Date.UTC(year, month, day, hour, minute, second, millisecond));
|
|
2499
|
+
} else {
|
|
2500
|
+
throw new Error("unrecognized options.timezone: " + options.timezone);
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
function getFileNameLowLevel(generalPurposeBitFlag, fileNameBuffer, extraFields, strictFileNames) {
|
|
2504
|
+
var fileName = null;
|
|
2505
|
+
for (var i = 0; i < extraFields.length; i++) {
|
|
2506
|
+
var extraField = extraFields[i];
|
|
2507
|
+
if (extraField.id === 28789) {
|
|
2508
|
+
if (extraField.data.length < 6) {
|
|
2509
|
+
continue;
|
|
2510
|
+
}
|
|
2511
|
+
if (extraField.data.readUInt8(0) !== 1) {
|
|
2512
|
+
continue;
|
|
2513
|
+
}
|
|
2514
|
+
var oldNameCrc32 = extraField.data.readUInt32LE(1);
|
|
2515
|
+
if (crc32(fileNameBuffer) !== oldNameCrc32) {
|
|
2516
|
+
continue;
|
|
2517
|
+
}
|
|
2518
|
+
fileName = decodeBuffer(extraField.data.subarray(5), true);
|
|
2519
|
+
break;
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
if (fileName == null) {
|
|
2523
|
+
var isUtf8 = (generalPurposeBitFlag & 2048) !== 0;
|
|
2524
|
+
fileName = decodeBuffer(fileNameBuffer, isUtf8);
|
|
2525
|
+
}
|
|
2526
|
+
if (!strictFileNames) {
|
|
2527
|
+
fileName = fileName.replace(/\\/g, "/");
|
|
2528
|
+
}
|
|
2529
|
+
return fileName;
|
|
2530
|
+
}
|
|
2531
|
+
function validateFileName(fileName) {
|
|
2532
|
+
if (fileName.indexOf("\\") !== -1) {
|
|
2533
|
+
return "invalid characters in fileName: " + fileName;
|
|
2534
|
+
}
|
|
2535
|
+
if (/^[a-zA-Z]:/.test(fileName) || /^\//.test(fileName)) {
|
|
2536
|
+
return "absolute path: " + fileName;
|
|
2537
|
+
}
|
|
2538
|
+
if (fileName.split("/").indexOf("..") !== -1) {
|
|
2539
|
+
return "invalid relative path: " + fileName;
|
|
2540
|
+
}
|
|
2541
|
+
return null;
|
|
2542
|
+
}
|
|
2543
|
+
function parseExtraFields(extraFieldBuffer) {
|
|
2544
|
+
var extraFields = [];
|
|
2545
|
+
var i = 0;
|
|
2546
|
+
while (i < extraFieldBuffer.length - 3) {
|
|
2547
|
+
var headerId = extraFieldBuffer.readUInt16LE(i + 0);
|
|
2548
|
+
var dataSize = extraFieldBuffer.readUInt16LE(i + 2);
|
|
2549
|
+
var dataStart = i + 4;
|
|
2550
|
+
var dataEnd = dataStart + dataSize;
|
|
2551
|
+
if (dataEnd > extraFieldBuffer.length) throw new Error("extra field length exceeds extra field buffer size");
|
|
2552
|
+
var dataBuffer = extraFieldBuffer.subarray(dataStart, dataEnd);
|
|
2553
|
+
extraFields.push({
|
|
2554
|
+
id: headerId,
|
|
2555
|
+
data: dataBuffer
|
|
2556
|
+
});
|
|
2557
|
+
i = dataEnd;
|
|
2558
|
+
}
|
|
2559
|
+
return extraFields;
|
|
2560
|
+
}
|
|
2561
|
+
function readAndAssertNoEof(reader, buffer, offset, length, position, callback) {
|
|
2562
|
+
if (length === 0) {
|
|
2563
|
+
return setImmediate(function() {
|
|
2564
|
+
callback(null, newBuffer(0));
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
reader.read(buffer, offset, length, position, function(err, bytesRead) {
|
|
2568
|
+
if (err) return callback(err);
|
|
2569
|
+
if (bytesRead < length) {
|
|
2570
|
+
return callback(new Error("unexpected EOF"));
|
|
2571
|
+
}
|
|
2572
|
+
callback();
|
|
2573
|
+
});
|
|
2574
|
+
}
|
|
2575
|
+
util.inherits(AssertByteCountStream, Transform);
|
|
2576
|
+
function AssertByteCountStream(byteCount) {
|
|
2577
|
+
Transform.call(this);
|
|
2578
|
+
this.actualByteCount = 0;
|
|
2579
|
+
this.expectedByteCount = byteCount;
|
|
2580
|
+
}
|
|
2581
|
+
AssertByteCountStream.prototype._transform = function(chunk, encoding, cb) {
|
|
2582
|
+
this.actualByteCount += chunk.length;
|
|
2583
|
+
if (this.actualByteCount > this.expectedByteCount) {
|
|
2584
|
+
var msg = "too many bytes in the stream. expected " + this.expectedByteCount + ". got at least " + this.actualByteCount;
|
|
2585
|
+
return cb(new Error(msg));
|
|
2586
|
+
}
|
|
2587
|
+
cb(null, chunk);
|
|
2588
|
+
};
|
|
2589
|
+
AssertByteCountStream.prototype._flush = function(cb) {
|
|
2590
|
+
if (this.actualByteCount < this.expectedByteCount) {
|
|
2591
|
+
var msg = "not enough bytes in the stream. expected " + this.expectedByteCount + ". got only " + this.actualByteCount;
|
|
2592
|
+
return cb(new Error(msg));
|
|
2593
|
+
}
|
|
2594
|
+
cb();
|
|
2595
|
+
};
|
|
2596
|
+
util.inherits(RandomAccessReader, EventEmitter);
|
|
2597
|
+
function RandomAccessReader() {
|
|
2598
|
+
EventEmitter.call(this);
|
|
2599
|
+
this.refCount = 0;
|
|
2600
|
+
}
|
|
2601
|
+
RandomAccessReader.prototype.ref = function() {
|
|
2602
|
+
this.refCount += 1;
|
|
2603
|
+
};
|
|
2604
|
+
RandomAccessReader.prototype.unref = function() {
|
|
2605
|
+
var self = this;
|
|
2606
|
+
self.refCount -= 1;
|
|
2607
|
+
if (self.refCount > 0) return;
|
|
2608
|
+
if (self.refCount < 0) throw new Error("invalid unref");
|
|
2609
|
+
self.close(onCloseDone);
|
|
2610
|
+
function onCloseDone(err) {
|
|
2611
|
+
if (err) return self.emit("error", err);
|
|
2612
|
+
self.emit("close");
|
|
2613
|
+
}
|
|
2614
|
+
};
|
|
2615
|
+
RandomAccessReader.prototype.createReadStream = function(options2) {
|
|
2616
|
+
if (options2 == null) options2 = {};
|
|
2617
|
+
var start = options2.start;
|
|
2618
|
+
var end = options2.end;
|
|
2619
|
+
if (start === end) {
|
|
2620
|
+
var emptyStream = new PassThrough();
|
|
2621
|
+
setImmediate(function() {
|
|
2622
|
+
emptyStream.end();
|
|
2623
|
+
});
|
|
2624
|
+
return emptyStream;
|
|
2625
|
+
}
|
|
2626
|
+
var stream = this._readStreamForRange(start, end);
|
|
2627
|
+
var destroyed = false;
|
|
2628
|
+
var refUnrefFilter = new RefUnrefFilter(this);
|
|
2629
|
+
stream.on("error", function(err) {
|
|
2630
|
+
setImmediate(function() {
|
|
2631
|
+
if (!destroyed) refUnrefFilter.emit("error", err);
|
|
2632
|
+
});
|
|
2633
|
+
});
|
|
2634
|
+
installDestroyFn(refUnrefFilter, function() {
|
|
2635
|
+
stream.unpipe(refUnrefFilter);
|
|
2636
|
+
refUnrefFilter.unref();
|
|
2637
|
+
stream.destroy();
|
|
2638
|
+
});
|
|
2639
|
+
var byteCounter = new AssertByteCountStream(end - start);
|
|
2640
|
+
refUnrefFilter.on("error", function(err) {
|
|
2641
|
+
setImmediate(function() {
|
|
2642
|
+
if (!destroyed) byteCounter.emit("error", err);
|
|
2643
|
+
});
|
|
2644
|
+
});
|
|
2645
|
+
installDestroyFn(byteCounter, function() {
|
|
2646
|
+
destroyed = true;
|
|
2647
|
+
refUnrefFilter.unpipe(byteCounter);
|
|
2648
|
+
refUnrefFilter.destroy();
|
|
2649
|
+
});
|
|
2650
|
+
return stream.pipe(refUnrefFilter).pipe(byteCounter);
|
|
2651
|
+
};
|
|
2652
|
+
RandomAccessReader.prototype._readStreamForRange = function(start, end) {
|
|
2653
|
+
throw new Error("not implemented");
|
|
2654
|
+
};
|
|
2655
|
+
RandomAccessReader.prototype.read = function(buffer, offset, length, position, callback) {
|
|
2656
|
+
var readStream = this.createReadStream({ start: position, end: position + length });
|
|
2657
|
+
var writeStream = new Writable();
|
|
2658
|
+
var written = 0;
|
|
2659
|
+
writeStream._write = function(chunk, encoding, cb) {
|
|
2660
|
+
chunk.copy(buffer, offset + written, 0, chunk.length);
|
|
2661
|
+
written += chunk.length;
|
|
2662
|
+
cb();
|
|
2663
|
+
};
|
|
2664
|
+
writeStream.on("finish", callback);
|
|
2665
|
+
readStream.on("error", function(error) {
|
|
2666
|
+
callback(error);
|
|
2667
|
+
});
|
|
2668
|
+
readStream.pipe(writeStream);
|
|
2669
|
+
};
|
|
2670
|
+
RandomAccessReader.prototype.close = function(callback) {
|
|
2671
|
+
setImmediate(callback);
|
|
2672
|
+
};
|
|
2673
|
+
util.inherits(RefUnrefFilter, PassThrough);
|
|
2674
|
+
function RefUnrefFilter(context) {
|
|
2675
|
+
PassThrough.call(this);
|
|
2676
|
+
this.context = context;
|
|
2677
|
+
this.context.ref();
|
|
2678
|
+
this.unreffedYet = false;
|
|
2679
|
+
}
|
|
2680
|
+
RefUnrefFilter.prototype._flush = function(cb) {
|
|
2681
|
+
this.unref();
|
|
2682
|
+
cb();
|
|
2683
|
+
};
|
|
2684
|
+
RefUnrefFilter.prototype.unref = function(cb) {
|
|
2685
|
+
if (this.unreffedYet) return;
|
|
2686
|
+
this.unreffedYet = true;
|
|
2687
|
+
this.context.unref();
|
|
2688
|
+
};
|
|
2689
|
+
var cp437 = "\0\u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\xB6\xA7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\xC7\xFC\xE9\xE2\xE4\xE0\xE5\xE7\xEA\xEB\xE8\xEF\xEE\xEC\xC4\xC5\xC9\xE6\xC6\xF4\xF6\xF2\xFB\xF9\xFF\xD6\xDC\xA2\xA3\xA5\u20A7\u0192\xE1\xED\xF3\xFA\xF1\xD1\xAA\xBA\xBF\u2310\xAC\xBD\xBC\xA1\xAB\xBB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\xDF\u0393\u03C0\u03A3\u03C3\xB5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\xB1\u2265\u2264\u2320\u2321\xF7\u2248\xB0\u2219\xB7\u221A\u207F\xB2\u25A0\xA0";
|
|
2690
|
+
function decodeBuffer(buffer, isUtf8) {
|
|
2691
|
+
if (isUtf8) {
|
|
2692
|
+
return buffer.toString("utf8");
|
|
2693
|
+
} else {
|
|
2694
|
+
var result = "";
|
|
2695
|
+
for (var i = 0; i < buffer.length; i++) {
|
|
2696
|
+
result += cp437[buffer[i]];
|
|
2697
|
+
}
|
|
2698
|
+
return result;
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
function readUInt64LE(buffer, offset) {
|
|
2702
|
+
var lower32 = buffer.readUInt32LE(offset);
|
|
2703
|
+
var upper32 = buffer.readUInt32LE(offset + 4);
|
|
2704
|
+
return upper32 * 4294967296 + lower32;
|
|
2705
|
+
}
|
|
2706
|
+
var newBuffer;
|
|
2707
|
+
if (typeof Buffer.allocUnsafe === "function") {
|
|
2708
|
+
newBuffer = function(len) {
|
|
2709
|
+
return Buffer.allocUnsafe(len);
|
|
2710
|
+
};
|
|
2711
|
+
} else {
|
|
2712
|
+
newBuffer = function(len) {
|
|
2713
|
+
return new Buffer(len);
|
|
2714
|
+
};
|
|
2715
|
+
}
|
|
2716
|
+
function installDestroyFn(stream, fn) {
|
|
2717
|
+
if (typeof stream.destroy === "function") {
|
|
2718
|
+
stream._destroy = function(err, cb) {
|
|
2719
|
+
fn();
|
|
2720
|
+
if (cb != null) cb(err);
|
|
2721
|
+
};
|
|
2722
|
+
} else {
|
|
2723
|
+
stream.destroy = fn;
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
function defaultCallback(err) {
|
|
2727
|
+
if (err) throw err;
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
});
|
|
2731
|
+
|
|
1383
2732
|
// ../../packages/node-runtime/src/import/write-parse-result.ts
|
|
1384
2733
|
function writeParseResultToDb(db, meta, members, messages) {
|
|
1385
2734
|
let messageCount = 0;
|
|
@@ -1592,8 +2941,8 @@ Errors: ${errorCount}
|
|
|
1592
2941
|
}
|
|
1593
2942
|
|
|
1594
2943
|
// ../../packages/parser/src/index.ts
|
|
1595
|
-
import * as
|
|
1596
|
-
import * as
|
|
2944
|
+
import * as fs18 from "fs";
|
|
2945
|
+
import * as path14 from "path";
|
|
1597
2946
|
|
|
1598
2947
|
// ../../packages/parser/src/sniffer.ts
|
|
1599
2948
|
import * as fs2 from "fs";
|
|
@@ -1647,9 +2996,9 @@ var FormatSniffer = class {
|
|
|
1647
2996
|
sniff(filePath) {
|
|
1648
2997
|
const ext = getExtension(filePath);
|
|
1649
2998
|
const headContent = readFileHead(filePath);
|
|
1650
|
-
for (const { feature:
|
|
1651
|
-
if (this.matchFeature(
|
|
1652
|
-
return
|
|
2999
|
+
for (const { feature: feature15 } of this.formats) {
|
|
3000
|
+
if (this.matchFeature(feature15, ext, headContent, filePath)) {
|
|
3001
|
+
return feature15;
|
|
1653
3002
|
}
|
|
1654
3003
|
}
|
|
1655
3004
|
return null;
|
|
@@ -1662,9 +3011,9 @@ var FormatSniffer = class {
|
|
|
1662
3011
|
getParser(filePath) {
|
|
1663
3012
|
const ext = getExtension(filePath);
|
|
1664
3013
|
const headContent = readFileHead(filePath);
|
|
1665
|
-
for (const { feature:
|
|
1666
|
-
if (this.matchFeature(
|
|
1667
|
-
return
|
|
3014
|
+
for (const { feature: feature15, parser: parser11 } of this.formats) {
|
|
3015
|
+
if (this.matchFeature(feature15, ext, headContent, filePath)) {
|
|
3016
|
+
return parser11;
|
|
1668
3017
|
}
|
|
1669
3018
|
}
|
|
1670
3019
|
return null;
|
|
@@ -1679,9 +3028,9 @@ var FormatSniffer = class {
|
|
|
1679
3028
|
const ext = getExtension(filePath);
|
|
1680
3029
|
const headContent = readFileHead(filePath);
|
|
1681
3030
|
const results = [];
|
|
1682
|
-
for (const { feature:
|
|
1683
|
-
if (this.matchFeature(
|
|
1684
|
-
results.push(
|
|
3031
|
+
for (const { feature: feature15 } of this.formats) {
|
|
3032
|
+
if (this.matchFeature(feature15, ext, headContent, filePath)) {
|
|
3033
|
+
results.push(feature15);
|
|
1685
3034
|
}
|
|
1686
3035
|
}
|
|
1687
3036
|
return results;
|
|
@@ -1696,9 +3045,9 @@ var FormatSniffer = class {
|
|
|
1696
3045
|
const ext = getExtension(filePath);
|
|
1697
3046
|
const headContent = readFileHead(filePath);
|
|
1698
3047
|
const results = [];
|
|
1699
|
-
for (const { feature:
|
|
1700
|
-
if (this.matchFeature(
|
|
1701
|
-
results.push(
|
|
3048
|
+
for (const { feature: feature15, parser: parser11 } of this.formats) {
|
|
3049
|
+
if (this.matchFeature(feature15, ext, headContent, filePath)) {
|
|
3050
|
+
results.push(parser11);
|
|
1702
3051
|
}
|
|
1703
3052
|
}
|
|
1704
3053
|
return results;
|
|
@@ -1719,11 +3068,11 @@ var FormatSniffer = class {
|
|
|
1719
3068
|
/**
|
|
1720
3069
|
* 检查特征是否匹配
|
|
1721
3070
|
*/
|
|
1722
|
-
matchFeature(
|
|
1723
|
-
if (!
|
|
3071
|
+
matchFeature(feature15, ext, headContent, filePath) {
|
|
3072
|
+
if (!feature15.extensions.includes(ext)) {
|
|
1724
3073
|
return false;
|
|
1725
3074
|
}
|
|
1726
|
-
const { signatures } =
|
|
3075
|
+
const { signatures } = feature15;
|
|
1727
3076
|
let headMatch = true;
|
|
1728
3077
|
if (signatures.head && signatures.head.length > 0) {
|
|
1729
3078
|
headMatch = matchHeadSignatures(headContent, signatures.head);
|
|
@@ -1826,8 +3175,8 @@ var feature = {
|
|
|
1826
3175
|
requiredFields: ["chatlab"]
|
|
1827
3176
|
}
|
|
1828
3177
|
};
|
|
1829
|
-
async function* parseChatLab(
|
|
1830
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
3178
|
+
async function* parseChatLab(options2) {
|
|
3179
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
1831
3180
|
const totalBytes = getFileSize(filePath);
|
|
1832
3181
|
let bytesRead = 0;
|
|
1833
3182
|
let messagesProcessed = 0;
|
|
@@ -1896,14 +3245,14 @@ async function* parseChatLab(options) {
|
|
|
1896
3245
|
}
|
|
1897
3246
|
const memberMapFromMessages = /* @__PURE__ */ new Map();
|
|
1898
3247
|
const messageBatch = [];
|
|
1899
|
-
await new Promise((
|
|
3248
|
+
await new Promise((resolve3, reject) => {
|
|
1900
3249
|
const readStream = fs4.createReadStream(filePath, { encoding: "utf-8" });
|
|
1901
3250
|
readStream.on("data", (chunk) => {
|
|
1902
3251
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
1903
3252
|
});
|
|
1904
|
-
const
|
|
3253
|
+
const pipeline2 = chain([readStream, parser(), pick({ filter: /^messages\.\d+$/ }), streamValues()]);
|
|
1905
3254
|
const batchCollector = [];
|
|
1906
|
-
|
|
3255
|
+
pipeline2.on("data", ({ value }) => {
|
|
1907
3256
|
const msg = value;
|
|
1908
3257
|
if (members.length === 0) {
|
|
1909
3258
|
memberMapFromMessages.set(msg.sender, {
|
|
@@ -1936,13 +3285,13 @@ async function* parseChatLab(options) {
|
|
|
1936
3285
|
onProgress?.(progress);
|
|
1937
3286
|
}
|
|
1938
3287
|
});
|
|
1939
|
-
|
|
3288
|
+
pipeline2.on("end", () => {
|
|
1940
3289
|
if (batchCollector.length > 0) {
|
|
1941
3290
|
messageBatch.push(...batchCollector);
|
|
1942
3291
|
}
|
|
1943
|
-
|
|
3292
|
+
resolve3();
|
|
1944
3293
|
});
|
|
1945
|
-
|
|
3294
|
+
pipeline2.on("error", reject);
|
|
1946
3295
|
});
|
|
1947
3296
|
if (members.length > 0) {
|
|
1948
3297
|
yield { type: "members", data: members };
|
|
@@ -2008,8 +3357,8 @@ var feature2 = {
|
|
|
2008
3357
|
head: [/^\s*\{.*"_type"\s*:\s*"header".*"chatlab"/]
|
|
2009
3358
|
}
|
|
2010
3359
|
};
|
|
2011
|
-
async function* parseChatLabJsonl(
|
|
2012
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
3360
|
+
async function* parseChatLabJsonl(options2) {
|
|
3361
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
2013
3362
|
const totalBytes = getFileSize(filePath);
|
|
2014
3363
|
let bytesRead = 0;
|
|
2015
3364
|
let messagesProcessed = 0;
|
|
@@ -2276,7 +3625,7 @@ async function preprocessQQJson(inputPath, onProgress) {
|
|
|
2276
3625
|
const outputPath = path5.join(tempDir, outputFilename);
|
|
2277
3626
|
onProgress?.(createProgress("parsing", 0, totalBytes, 0, ""));
|
|
2278
3627
|
const avatarsStr = readAvatarsFromFile(inputPath);
|
|
2279
|
-
return new Promise((
|
|
3628
|
+
return new Promise((resolve3, reject) => {
|
|
2280
3629
|
const headChunks = [];
|
|
2281
3630
|
let headSize = 0;
|
|
2282
3631
|
const maxHeadSize = 1e5;
|
|
@@ -2326,8 +3675,8 @@ async function preprocessQQJson(inputPath, onProgress) {
|
|
|
2326
3675
|
const headerJson = JSON.stringify(header);
|
|
2327
3676
|
writeStream.write(headerJson.slice(0, -2) + "\n");
|
|
2328
3677
|
let isFirstMessage = true;
|
|
2329
|
-
const
|
|
2330
|
-
|
|
3678
|
+
const pipeline2 = chain2([readStream, parser3(), pick2({ filter: /^messages\.\d+$/ }), streamValues2()]);
|
|
3679
|
+
pipeline2.on("data", ({ value }) => {
|
|
2331
3680
|
const slimMsg = slimMessage(value);
|
|
2332
3681
|
const msgJson = JSON.stringify(slimMsg);
|
|
2333
3682
|
if (isFirstMessage) {
|
|
@@ -2349,7 +3698,7 @@ async function preprocessQQJson(inputPath, onProgress) {
|
|
|
2349
3698
|
);
|
|
2350
3699
|
}
|
|
2351
3700
|
});
|
|
2352
|
-
|
|
3701
|
+
pipeline2.on("end", () => {
|
|
2353
3702
|
writeStream.write("\n]");
|
|
2354
3703
|
if (avatarsStr) {
|
|
2355
3704
|
writeStream.write(',"avatars":' + avatarsStr);
|
|
@@ -2358,10 +3707,10 @@ async function preprocessQQJson(inputPath, onProgress) {
|
|
|
2358
3707
|
writeStream.end();
|
|
2359
3708
|
writeStream.on("finish", () => {
|
|
2360
3709
|
onProgress?.(createProgress("done", totalBytes, totalBytes, messagesProcessed, ""));
|
|
2361
|
-
|
|
3710
|
+
resolve3(outputPath);
|
|
2362
3711
|
});
|
|
2363
3712
|
});
|
|
2364
|
-
|
|
3713
|
+
pipeline2.on("error", (err) => {
|
|
2365
3714
|
writeStream.destroy();
|
|
2366
3715
|
if (fs6.existsSync(outputPath)) {
|
|
2367
3716
|
fs6.unlinkSync(outputPath);
|
|
@@ -2496,8 +3845,8 @@ function convertMessageType(messageType, content, isRecalled) {
|
|
|
2496
3845
|
if (messageType === 9) return 25 /* REPLY */;
|
|
2497
3846
|
return 0 /* TEXT */;
|
|
2498
3847
|
}
|
|
2499
|
-
async function* parseV4(
|
|
2500
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
3848
|
+
async function* parseV4(options2) {
|
|
3849
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
2501
3850
|
const totalBytes = getFileSize(filePath);
|
|
2502
3851
|
let bytesRead = 0;
|
|
2503
3852
|
let messagesProcessed = 0;
|
|
@@ -2527,13 +3876,13 @@ async function* parseV4(options) {
|
|
|
2527
3876
|
yield { type: "meta", data: meta };
|
|
2528
3877
|
const memberMap = /* @__PURE__ */ new Map();
|
|
2529
3878
|
const messageBatch = [];
|
|
2530
|
-
await new Promise((
|
|
3879
|
+
await new Promise((resolve3, reject) => {
|
|
2531
3880
|
const readStream = fs7.createReadStream(filePath, { encoding: "utf-8" });
|
|
2532
3881
|
readStream.on("data", (chunk) => {
|
|
2533
3882
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
2534
3883
|
});
|
|
2535
|
-
const
|
|
2536
|
-
|
|
3884
|
+
const pipeline2 = chain3([readStream, parser4(), pick3({ filter: /^messages\.\d+$/ }), streamValues3()]);
|
|
3885
|
+
pipeline2.on("data", ({ value }) => {
|
|
2537
3886
|
const platformId = value.sender.uin || value.sender.uid || value.rawMessage?.senderUin || value.rawMessage?.senderUid;
|
|
2538
3887
|
if (!platformId) {
|
|
2539
3888
|
skippedMessages++;
|
|
@@ -2581,8 +3930,8 @@ async function* parseV4(options) {
|
|
|
2581
3930
|
onProgress?.(progress);
|
|
2582
3931
|
}
|
|
2583
3932
|
});
|
|
2584
|
-
|
|
2585
|
-
|
|
3933
|
+
pipeline2.on("end", resolve3);
|
|
3934
|
+
pipeline2.on("error", reject);
|
|
2586
3935
|
});
|
|
2587
3936
|
const avatarsMap = /* @__PURE__ */ new Map();
|
|
2588
3937
|
try {
|
|
@@ -2770,8 +4119,8 @@ async function* readJsonlFile(filePath, onParseError) {
|
|
|
2770
4119
|
}
|
|
2771
4120
|
}
|
|
2772
4121
|
}
|
|
2773
|
-
async function* parseChunkedJsonl(
|
|
2774
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
4122
|
+
async function* parseChunkedJsonl(options2) {
|
|
4123
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
2775
4124
|
const manifestPath = filePath;
|
|
2776
4125
|
const baseDir = path7.dirname(manifestPath);
|
|
2777
4126
|
onLog?.("info", `\u5F00\u59CB\u89E3\u6790 manifest: ${manifestPath}`);
|
|
@@ -3044,8 +4393,8 @@ function convertMessageType3(typeStr) {
|
|
|
3044
4393
|
return 99 /* OTHER */;
|
|
3045
4394
|
}
|
|
3046
4395
|
}
|
|
3047
|
-
async function* parseWeFlow(
|
|
3048
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
4396
|
+
async function* parseWeFlow(options2) {
|
|
4397
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
3049
4398
|
const totalBytes = getFileSize(filePath);
|
|
3050
4399
|
let bytesRead = 0;
|
|
3051
4400
|
let messagesProcessed = 0;
|
|
@@ -3056,7 +4405,7 @@ async function* parseWeFlow(options) {
|
|
|
3056
4405
|
const headContent = readFileHeadBytes(filePath, 5e3);
|
|
3057
4406
|
let session = null;
|
|
3058
4407
|
try {
|
|
3059
|
-
await new Promise((
|
|
4408
|
+
await new Promise((resolve3) => {
|
|
3060
4409
|
const sessionStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
|
|
3061
4410
|
let sessionContent = "";
|
|
3062
4411
|
let inSession = false;
|
|
@@ -3108,9 +4457,9 @@ async function* parseWeFlow(options) {
|
|
|
3108
4457
|
} catch {
|
|
3109
4458
|
}
|
|
3110
4459
|
}
|
|
3111
|
-
|
|
4460
|
+
resolve3();
|
|
3112
4461
|
});
|
|
3113
|
-
sessionStream.on("error", () =>
|
|
4462
|
+
sessionStream.on("error", () => resolve3());
|
|
3114
4463
|
});
|
|
3115
4464
|
} catch {
|
|
3116
4465
|
}
|
|
@@ -3179,7 +4528,7 @@ async function* parseWeFlow(options) {
|
|
|
3179
4528
|
}
|
|
3180
4529
|
if (avatarsMap.size === 0) {
|
|
3181
4530
|
try {
|
|
3182
|
-
await new Promise((
|
|
4531
|
+
await new Promise((resolve3) => {
|
|
3183
4532
|
const avatarStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
|
|
3184
4533
|
let avatarsContent = "";
|
|
3185
4534
|
let inAvatars = false;
|
|
@@ -3236,9 +4585,9 @@ async function* parseWeFlow(options) {
|
|
|
3236
4585
|
} catch {
|
|
3237
4586
|
}
|
|
3238
4587
|
}
|
|
3239
|
-
|
|
4588
|
+
resolve3();
|
|
3240
4589
|
});
|
|
3241
|
-
avatarStream.on("error", () =>
|
|
4590
|
+
avatarStream.on("error", () => resolve3());
|
|
3242
4591
|
});
|
|
3243
4592
|
} catch {
|
|
3244
4593
|
}
|
|
@@ -3246,7 +4595,7 @@ async function* parseWeFlow(options) {
|
|
|
3246
4595
|
const groupAvatar = sessionData?.avatar || (groupId ? avatarsMap.get(groupId) : void 0);
|
|
3247
4596
|
let ownerId;
|
|
3248
4597
|
try {
|
|
3249
|
-
await new Promise((
|
|
4598
|
+
await new Promise((resolve3) => {
|
|
3250
4599
|
const scanStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
|
|
3251
4600
|
const scanPipeline = chain4([scanStream, parser5(), pick4({ filter: /^messages\.\d+$/ }), streamValues4()]);
|
|
3252
4601
|
scanPipeline.on("data", ({ value }) => {
|
|
@@ -3255,9 +4604,9 @@ async function* parseWeFlow(options) {
|
|
|
3255
4604
|
scanStream.destroy();
|
|
3256
4605
|
}
|
|
3257
4606
|
});
|
|
3258
|
-
scanStream.on("close", () =>
|
|
3259
|
-
scanPipeline.on("end", () =>
|
|
3260
|
-
scanPipeline.on("error", () =>
|
|
4607
|
+
scanStream.on("close", () => resolve3());
|
|
4608
|
+
scanPipeline.on("end", () => resolve3());
|
|
4609
|
+
scanPipeline.on("error", () => resolve3());
|
|
3261
4610
|
});
|
|
3262
4611
|
} catch {
|
|
3263
4612
|
}
|
|
@@ -3272,12 +4621,12 @@ async function* parseWeFlow(options) {
|
|
|
3272
4621
|
yield { type: "meta", data: meta };
|
|
3273
4622
|
const memberMap = /* @__PURE__ */ new Map();
|
|
3274
4623
|
const messageBatch = [];
|
|
3275
|
-
await new Promise((
|
|
4624
|
+
await new Promise((resolve3, reject) => {
|
|
3276
4625
|
const readStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
|
|
3277
4626
|
readStream.on("data", (chunk) => {
|
|
3278
4627
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
3279
4628
|
});
|
|
3280
|
-
const
|
|
4629
|
+
const pipeline2 = chain4([readStream, parser5(), pick4({ filter: /^messages\.\d+$/ }), streamValues4()]);
|
|
3281
4630
|
const processMessage = (msg) => {
|
|
3282
4631
|
if (!msg.senderUsername || msg.createTime === void 0) {
|
|
3283
4632
|
return null;
|
|
@@ -3322,7 +4671,7 @@ async function* parseWeFlow(options) {
|
|
|
3322
4671
|
};
|
|
3323
4672
|
};
|
|
3324
4673
|
const batchCollector = [];
|
|
3325
|
-
|
|
4674
|
+
pipeline2.on("data", ({ value }) => {
|
|
3326
4675
|
const parsed = processMessage(value);
|
|
3327
4676
|
if (parsed) {
|
|
3328
4677
|
batchCollector.push(parsed);
|
|
@@ -3341,13 +4690,13 @@ async function* parseWeFlow(options) {
|
|
|
3341
4690
|
}
|
|
3342
4691
|
}
|
|
3343
4692
|
});
|
|
3344
|
-
|
|
4693
|
+
pipeline2.on("end", () => {
|
|
3345
4694
|
if (batchCollector.length > 0) {
|
|
3346
4695
|
messageBatch.push(...batchCollector);
|
|
3347
4696
|
}
|
|
3348
|
-
|
|
4697
|
+
resolve3();
|
|
3349
4698
|
});
|
|
3350
|
-
|
|
4699
|
+
pipeline2.on("error", reject);
|
|
3351
4700
|
});
|
|
3352
4701
|
const members = Array.from(memberMap.values()).map((m) => ({
|
|
3353
4702
|
platformId: m.platformId,
|
|
@@ -3521,8 +4870,8 @@ function convertRoles(discordRoles) {
|
|
|
3521
4870
|
name: role.name
|
|
3522
4871
|
}));
|
|
3523
4872
|
}
|
|
3524
|
-
async function* parseDiscordExporter(
|
|
3525
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
4873
|
+
async function* parseDiscordExporter(options2) {
|
|
4874
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
3526
4875
|
const totalBytes = getFileSize(filePath);
|
|
3527
4876
|
let bytesRead = 0;
|
|
3528
4877
|
let messagesProcessed = 0;
|
|
@@ -3558,14 +4907,14 @@ async function* parseDiscordExporter(options) {
|
|
|
3558
4907
|
onLog?.("info", `\u7FA4\u804A\u540D\u79F0: ${chatName}`);
|
|
3559
4908
|
const memberMap = /* @__PURE__ */ new Map();
|
|
3560
4909
|
const messageBatch = [];
|
|
3561
|
-
await new Promise((
|
|
4910
|
+
await new Promise((resolve3, reject) => {
|
|
3562
4911
|
const readStream = fs10.createReadStream(filePath, { encoding: "utf-8" });
|
|
3563
4912
|
readStream.on("data", (chunk) => {
|
|
3564
4913
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
3565
4914
|
});
|
|
3566
|
-
const
|
|
4915
|
+
const pipeline2 = chain5([readStream, parser6(), pick5({ filter: /^messages\.\d+$/ }), streamValues5()]);
|
|
3567
4916
|
const batchCollector = [];
|
|
3568
|
-
|
|
4917
|
+
pipeline2.on("data", ({ value }) => {
|
|
3569
4918
|
const msg = value;
|
|
3570
4919
|
const author = msg.author;
|
|
3571
4920
|
if (!memberMap.has(author.id)) {
|
|
@@ -3633,13 +4982,13 @@ ${stickerTexts.join("\n")}` : stickerTexts.join("\n");
|
|
|
3633
4982
|
onProgress?.(progress);
|
|
3634
4983
|
}
|
|
3635
4984
|
});
|
|
3636
|
-
|
|
4985
|
+
pipeline2.on("end", () => {
|
|
3637
4986
|
if (batchCollector.length > 0) {
|
|
3638
4987
|
messageBatch.push(...batchCollector);
|
|
3639
4988
|
}
|
|
3640
|
-
|
|
4989
|
+
resolve3();
|
|
3641
4990
|
});
|
|
3642
|
-
|
|
4991
|
+
pipeline2.on("error", reject);
|
|
3643
4992
|
});
|
|
3644
4993
|
const members = Array.from(memberMap.values());
|
|
3645
4994
|
yield { type: "members", data: members };
|
|
@@ -3760,10 +5109,10 @@ var feature8 = {
|
|
|
3760
5109
|
};
|
|
3761
5110
|
async function scanChats(filePath) {
|
|
3762
5111
|
const chats = [];
|
|
3763
|
-
return new Promise((
|
|
5112
|
+
return new Promise((resolve3, reject) => {
|
|
3764
5113
|
const readStream = fs11.createReadStream(filePath, { encoding: "utf-8" });
|
|
3765
|
-
const
|
|
3766
|
-
|
|
5114
|
+
const pipeline2 = chain6([readStream, parser7(), pick6({ filter: /^chats\.list\.\d+$/ }), streamValues6()]);
|
|
5115
|
+
pipeline2.on("data", ({ value }) => {
|
|
3767
5116
|
const chat = value;
|
|
3768
5117
|
chats.push({
|
|
3769
5118
|
index: chats.length,
|
|
@@ -3773,16 +5122,16 @@ async function scanChats(filePath) {
|
|
|
3773
5122
|
messageCount: Array.isArray(chat.messages) ? chat.messages.length : 0
|
|
3774
5123
|
});
|
|
3775
5124
|
});
|
|
3776
|
-
|
|
3777
|
-
|
|
5125
|
+
pipeline2.on("end", () => {
|
|
5126
|
+
resolve3(chats);
|
|
3778
5127
|
});
|
|
3779
|
-
|
|
5128
|
+
pipeline2.on("error", (err) => {
|
|
3780
5129
|
reject(new Error(`\u626B\u63CF Telegram \u6587\u4EF6\u5931\u8D25: ${err.message}`));
|
|
3781
5130
|
});
|
|
3782
5131
|
});
|
|
3783
5132
|
}
|
|
3784
|
-
async function* parseTelegram(
|
|
3785
|
-
const { filePath, batchSize = 5e3, formatOptions, onProgress, onLog } =
|
|
5133
|
+
async function* parseTelegram(options2) {
|
|
5134
|
+
const { filePath, batchSize = 5e3, formatOptions, onProgress, onLog } = options2;
|
|
3786
5135
|
const chatIndex = formatOptions?.chatIndex ?? 0;
|
|
3787
5136
|
const totalBytes = getFileSize(filePath);
|
|
3788
5137
|
let bytesRead = 0;
|
|
@@ -3793,26 +5142,26 @@ async function* parseTelegram(options) {
|
|
|
3793
5142
|
onLog?.("info", `\u5F00\u59CB\u89E3\u6790 Telegram JSON \u6587\u4EF6\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
3794
5143
|
onLog?.("info", `\u76EE\u6807\u804A\u5929\u7D22\u5F15: ${chatIndex}`);
|
|
3795
5144
|
const chatPathFilter = `chats.list.${chatIndex}`;
|
|
3796
|
-
const chatData = await new Promise((
|
|
5145
|
+
const chatData = await new Promise((resolve3, reject) => {
|
|
3797
5146
|
const readStream = fs11.createReadStream(filePath, { encoding: "utf-8" });
|
|
3798
5147
|
readStream.on("data", (chunk) => {
|
|
3799
5148
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
3800
5149
|
});
|
|
3801
|
-
const
|
|
5150
|
+
const pipeline2 = chain6([
|
|
3802
5151
|
readStream,
|
|
3803
5152
|
parser7(),
|
|
3804
5153
|
pick6({ filter: new RegExp(`^${chatPathFilter.replace(".", "\\.")}$`) }),
|
|
3805
5154
|
streamValues6()
|
|
3806
5155
|
]);
|
|
3807
5156
|
let found = false;
|
|
3808
|
-
|
|
5157
|
+
pipeline2.on("data", ({ value }) => {
|
|
3809
5158
|
found = true;
|
|
3810
|
-
|
|
5159
|
+
resolve3(value);
|
|
3811
5160
|
});
|
|
3812
|
-
|
|
3813
|
-
if (!found)
|
|
5161
|
+
pipeline2.on("end", () => {
|
|
5162
|
+
if (!found) resolve3(null);
|
|
3814
5163
|
});
|
|
3815
|
-
|
|
5164
|
+
pipeline2.on("error", reject);
|
|
3816
5165
|
});
|
|
3817
5166
|
if (!chatData) {
|
|
3818
5167
|
onLog?.("error", `\u672A\u627E\u5230\u7D22\u5F15 ${chatIndex} \u5BF9\u5E94\u7684\u804A\u5929`);
|
|
@@ -3923,28 +5272,28 @@ var feature9 = {
|
|
|
3923
5272
|
}
|
|
3924
5273
|
}
|
|
3925
5274
|
};
|
|
3926
|
-
async function* parseTelegramSingle(
|
|
3927
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
5275
|
+
async function* parseTelegramSingle(options2) {
|
|
5276
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
3928
5277
|
const totalBytes = getFileSize(filePath);
|
|
3929
5278
|
let messagesProcessed = 0;
|
|
3930
5279
|
const initialProgress = createProgress("parsing", 0, totalBytes, 0, "");
|
|
3931
5280
|
yield { type: "progress", data: initialProgress };
|
|
3932
5281
|
onProgress?.(initialProgress);
|
|
3933
5282
|
onLog?.("info", `\u5F00\u59CB\u89E3\u6790 Telegram \u5355\u804A\u5929 JSON \u6587\u4EF6\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
3934
|
-
const chatData = await new Promise((
|
|
5283
|
+
const chatData = await new Promise((resolve3, reject) => {
|
|
3935
5284
|
const readStream = fs12.createReadStream(filePath, { encoding: "utf-8" });
|
|
3936
|
-
const
|
|
5285
|
+
const pipeline2 = chain7([readStream, parser8(), streamValues7()]);
|
|
3937
5286
|
let found = false;
|
|
3938
|
-
|
|
5287
|
+
pipeline2.on("data", ({ value }) => {
|
|
3939
5288
|
if (!found) {
|
|
3940
5289
|
found = true;
|
|
3941
|
-
|
|
5290
|
+
resolve3(value);
|
|
3942
5291
|
}
|
|
3943
5292
|
});
|
|
3944
|
-
|
|
3945
|
-
if (!found)
|
|
5293
|
+
pipeline2.on("end", () => {
|
|
5294
|
+
if (!found) resolve3(null);
|
|
3946
5295
|
});
|
|
3947
|
-
|
|
5296
|
+
pipeline2.on("error", reject);
|
|
3948
5297
|
});
|
|
3949
5298
|
if (!chatData) {
|
|
3950
5299
|
onLog?.("error", "\u65E0\u6CD5\u89E3\u6790 Telegram \u5355\u804A\u5929\u6587\u4EF6");
|
|
@@ -4202,8 +5551,8 @@ function parseV1Timestamp(timeStr) {
|
|
|
4202
5551
|
const ts = Math.floor(date.getTime() / 1e3);
|
|
4203
5552
|
return isNaN(ts) ? 0 : ts;
|
|
4204
5553
|
}
|
|
4205
|
-
async function* parseWhatsApp(
|
|
4206
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
5554
|
+
async function* parseWhatsApp(options2) {
|
|
5555
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
4207
5556
|
const totalBytes = getFileSize(filePath);
|
|
4208
5557
|
let bytesRead = 0;
|
|
4209
5558
|
let messagesProcessed = 0;
|
|
@@ -4410,8 +5759,8 @@ function cleanNickname(nickname) {
|
|
|
4410
5759
|
return nickname.replace(/^(【[^】]*】\s*)+/, "").trim();
|
|
4411
5760
|
}
|
|
4412
5761
|
var lastValidNickname = /* @__PURE__ */ new Map();
|
|
4413
|
-
async function* parseTxt(
|
|
4414
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
5762
|
+
async function* parseTxt(options2) {
|
|
5763
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
4415
5764
|
const totalBytes = getFileSize(filePath);
|
|
4416
5765
|
let bytesRead = 0;
|
|
4417
5766
|
let messagesProcessed = 0;
|
|
@@ -4630,8 +5979,8 @@ function getMessageContent(msg) {
|
|
|
4630
5979
|
}
|
|
4631
5980
|
return "[\u672A\u77E5\u6D88\u606F]";
|
|
4632
5981
|
}
|
|
4633
|
-
async function* parseInstagram(
|
|
4634
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
5982
|
+
async function* parseInstagram(options2) {
|
|
5983
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
4635
5984
|
const totalBytes = getFileSize(filePath);
|
|
4636
5985
|
let messagesProcessed = 0;
|
|
4637
5986
|
const initialProgress = createProgress("parsing", 0, totalBytes, 0, "\u6B63\u5728\u89E3\u6790 Instagram \u804A\u5929\u8BB0\u5F55...");
|
|
@@ -4730,10 +6079,247 @@ var module_12 = {
|
|
|
4730
6079
|
};
|
|
4731
6080
|
var instagram_native_default = module_12;
|
|
4732
6081
|
|
|
4733
|
-
// ../../packages/parser/src/formats/
|
|
6082
|
+
// ../../packages/parser/src/formats/google-chat-takeout.ts
|
|
6083
|
+
var import_stream_chain8 = __toESM(require_stream_chain(), 1);
|
|
6084
|
+
var import_stream_json8 = __toESM(require_stream_json(), 1);
|
|
6085
|
+
var import_Pick7 = __toESM(require_Pick(), 1);
|
|
6086
|
+
var import_StreamValues8 = __toESM(require_StreamValues(), 1);
|
|
4734
6087
|
import * as fs16 from "fs";
|
|
4735
6088
|
import * as path12 from "path";
|
|
6089
|
+
var { chain: chain8 } = import_stream_chain8.default;
|
|
6090
|
+
var { parser: parser9 } = import_stream_json8.default;
|
|
6091
|
+
var { pick: pick7 } = import_Pick7.default;
|
|
6092
|
+
var { streamValues: streamValues8 } = import_StreamValues8.default;
|
|
6093
|
+
var ENGLISH_MONTHS = /* @__PURE__ */ new Map([
|
|
6094
|
+
["january", 0],
|
|
6095
|
+
["february", 1],
|
|
6096
|
+
["march", 2],
|
|
6097
|
+
["april", 3],
|
|
6098
|
+
["may", 4],
|
|
6099
|
+
["june", 5],
|
|
6100
|
+
["july", 6],
|
|
6101
|
+
["august", 7],
|
|
6102
|
+
["september", 8],
|
|
6103
|
+
["october", 9],
|
|
6104
|
+
["november", 10],
|
|
6105
|
+
["december", 11]
|
|
6106
|
+
]);
|
|
4736
6107
|
var feature13 = {
|
|
6108
|
+
id: "google-chat-takeout",
|
|
6109
|
+
name: "Google Chat Takeout",
|
|
6110
|
+
platform: KNOWN_PLATFORMS.GOOGLE_CHAT,
|
|
6111
|
+
priority: 24,
|
|
6112
|
+
extensions: [".json"],
|
|
6113
|
+
signatures: {
|
|
6114
|
+
head: [/"format"\s*:\s*"chatlab-google-chat-takeout"/],
|
|
6115
|
+
requiredFields: ["format", "version", "messagesFile"]
|
|
6116
|
+
}
|
|
6117
|
+
};
|
|
6118
|
+
function normalizeSpaces(value) {
|
|
6119
|
+
return value.replace(/[\u00a0\u202f]/g, " ").replace(/\s+/g, " ").trim();
|
|
6120
|
+
}
|
|
6121
|
+
function createUtcTimestamp(year, monthIndex, day, hour, minute, second) {
|
|
6122
|
+
const timestampMs = Date.UTC(year, monthIndex, day, hour, minute, second);
|
|
6123
|
+
const date = new Date(timestampMs);
|
|
6124
|
+
if (date.getUTCFullYear() !== year || date.getUTCMonth() !== monthIndex || date.getUTCDate() !== day || date.getUTCHours() !== hour || date.getUTCMinutes() !== minute || date.getUTCSeconds() !== second) {
|
|
6125
|
+
return null;
|
|
6126
|
+
}
|
|
6127
|
+
return Math.floor(timestampMs / 1e3);
|
|
6128
|
+
}
|
|
6129
|
+
function parseChineseUtcDate(value) {
|
|
6130
|
+
const match = normalizeSpaces(value).match(
|
|
6131
|
+
/^(\d{4})年(\d{1,2})月(\d{1,2})日(?:星期[一二三四五六日天])?\s+UTC\s+(\d{1,2}):(\d{2}):(\d{2})$/
|
|
6132
|
+
);
|
|
6133
|
+
if (!match) return null;
|
|
6134
|
+
return createUtcTimestamp(
|
|
6135
|
+
Number(match[1]),
|
|
6136
|
+
Number(match[2]) - 1,
|
|
6137
|
+
Number(match[3]),
|
|
6138
|
+
Number(match[4]),
|
|
6139
|
+
Number(match[5]),
|
|
6140
|
+
Number(match[6])
|
|
6141
|
+
);
|
|
6142
|
+
}
|
|
6143
|
+
function parseEnglishUtcDate(value) {
|
|
6144
|
+
const match = normalizeSpaces(value).match(
|
|
6145
|
+
/^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday),\s+([A-Za-z]+)\s+(\d{1,2}),\s+(\d{4})\s+at\s+(\d{1,2}):(\d{2}):(\d{2})\s+(AM|PM)\s+UTC$/i
|
|
6146
|
+
);
|
|
6147
|
+
if (!match) return null;
|
|
6148
|
+
const monthIndex = ENGLISH_MONTHS.get(match[1].toLowerCase());
|
|
6149
|
+
if (monthIndex === void 0) return null;
|
|
6150
|
+
let hour = Number(match[4]);
|
|
6151
|
+
if (hour < 1 || hour > 12) return null;
|
|
6152
|
+
if (match[7].toUpperCase() === "AM") {
|
|
6153
|
+
if (hour === 12) hour = 0;
|
|
6154
|
+
} else if (hour !== 12) {
|
|
6155
|
+
hour += 12;
|
|
6156
|
+
}
|
|
6157
|
+
return createUtcTimestamp(Number(match[3]), monthIndex, Number(match[2]), hour, Number(match[5]), Number(match[6]));
|
|
6158
|
+
}
|
|
6159
|
+
function parseGoogleChatDate(value) {
|
|
6160
|
+
return parseChineseUtcDate(value) ?? parseEnglishUtcDate(value);
|
|
6161
|
+
}
|
|
6162
|
+
function normalizeIdentity(user) {
|
|
6163
|
+
const email = user?.email?.trim().toLowerCase();
|
|
6164
|
+
const name = user?.name?.trim() || email || "Unknown";
|
|
6165
|
+
return {
|
|
6166
|
+
platformId: email || name.toLowerCase(),
|
|
6167
|
+
name
|
|
6168
|
+
};
|
|
6169
|
+
}
|
|
6170
|
+
function readJson(filePath) {
|
|
6171
|
+
return JSON.parse(fs16.readFileSync(filePath, "utf8"));
|
|
6172
|
+
}
|
|
6173
|
+
function resolveManifestFile(manifestDir, relativePath) {
|
|
6174
|
+
const resolved = path12.resolve(manifestDir, relativePath);
|
|
6175
|
+
const relative2 = path12.relative(manifestDir, resolved);
|
|
6176
|
+
if (relative2.startsWith("..") || path12.isAbsolute(relative2)) {
|
|
6177
|
+
throw new Error(`Google Chat manifest path escapes its directory: ${relativePath}`);
|
|
6178
|
+
}
|
|
6179
|
+
return resolved;
|
|
6180
|
+
}
|
|
6181
|
+
function readManifest2(filePath) {
|
|
6182
|
+
const manifest = readJson(filePath);
|
|
6183
|
+
if (manifest.format !== "chatlab-google-chat-takeout" || manifest.version !== 1) {
|
|
6184
|
+
throw new Error("Invalid Google Chat import manifest");
|
|
6185
|
+
}
|
|
6186
|
+
if (manifest.chatType !== "private" && manifest.chatType !== "group") {
|
|
6187
|
+
throw new Error("Invalid Google Chat chat type");
|
|
6188
|
+
}
|
|
6189
|
+
const manifestDir = path12.dirname(filePath);
|
|
6190
|
+
return {
|
|
6191
|
+
manifest,
|
|
6192
|
+
userInfoPath: resolveManifestFile(manifestDir, manifest.userInfoFile),
|
|
6193
|
+
groupInfoPath: resolveManifestFile(manifestDir, manifest.groupInfoFile),
|
|
6194
|
+
messagesPath: resolveManifestFile(manifestDir, manifest.messagesFile)
|
|
6195
|
+
};
|
|
6196
|
+
}
|
|
6197
|
+
function getAttachmentName(attachment) {
|
|
6198
|
+
return attachment.original_name?.trim() || attachment.export_name?.trim() || null;
|
|
6199
|
+
}
|
|
6200
|
+
function buildQuotePrefix(message) {
|
|
6201
|
+
const quote = message.quoted_message_metadata;
|
|
6202
|
+
const quoteText = quote?.text?.trim();
|
|
6203
|
+
if (!quoteText) return null;
|
|
6204
|
+
const creator = quote?.creator?.name?.trim() || quote?.creator?.email?.trim();
|
|
6205
|
+
return creator ? `> ${creator}: ${quoteText}` : `> ${quoteText}`;
|
|
6206
|
+
}
|
|
6207
|
+
function buildMessageContent(message) {
|
|
6208
|
+
const parts = [];
|
|
6209
|
+
const quote = buildQuotePrefix(message);
|
|
6210
|
+
if (quote) parts.push(quote);
|
|
6211
|
+
const text = message.text?.trim();
|
|
6212
|
+
if (text) parts.push(text);
|
|
6213
|
+
for (const attachment of message.attached_files ?? []) {
|
|
6214
|
+
const name = getAttachmentName(attachment);
|
|
6215
|
+
if (name) parts.push(`[\u9644\u4EF6] ${name}`);
|
|
6216
|
+
}
|
|
6217
|
+
return parts.length > 0 ? parts.join("\n") : "[\u4E0D\u652F\u6301\u7684 Google Chat \u6D88\u606F]";
|
|
6218
|
+
}
|
|
6219
|
+
function detectMessageType5(message) {
|
|
6220
|
+
if (message.text?.trim()) return 0 /* TEXT */;
|
|
6221
|
+
if ((message.attached_files ?? []).some((attachment) => getAttachmentName(attachment))) {
|
|
6222
|
+
return 4 /* FILE */;
|
|
6223
|
+
}
|
|
6224
|
+
return 99 /* OTHER */;
|
|
6225
|
+
}
|
|
6226
|
+
function deriveChatName(manifest, groupInfo, ownerId) {
|
|
6227
|
+
if (manifest.chatName?.trim()) return manifest.chatName.trim();
|
|
6228
|
+
if (manifest.chatType === "group" && groupInfo.name?.trim()) return groupInfo.name.trim();
|
|
6229
|
+
const otherMember = (groupInfo.members ?? []).map(normalizeIdentity).find((member) => !ownerId || member.platformId !== ownerId);
|
|
6230
|
+
return otherMember?.name || groupInfo.members?.map((member) => normalizeIdentity(member).name).join(", ") || manifest.chatId;
|
|
6231
|
+
}
|
|
6232
|
+
async function* parseGoogleChat(options2) {
|
|
6233
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
6234
|
+
const { manifest, userInfoPath, groupInfoPath, messagesPath } = readManifest2(filePath);
|
|
6235
|
+
const userInfo = readJson(userInfoPath);
|
|
6236
|
+
const groupInfo = readJson(groupInfoPath);
|
|
6237
|
+
const owner = userInfo.user ? normalizeIdentity(userInfo.user) : null;
|
|
6238
|
+
const totalBytes = getFileSize(messagesPath);
|
|
6239
|
+
const initialProgress = createProgress("parsing", 0, totalBytes, 0, "");
|
|
6240
|
+
yield { type: "progress", data: initialProgress };
|
|
6241
|
+
onProgress?.(initialProgress);
|
|
6242
|
+
yield {
|
|
6243
|
+
type: "meta",
|
|
6244
|
+
data: {
|
|
6245
|
+
name: deriveChatName(manifest, groupInfo, owner?.platformId),
|
|
6246
|
+
platform: KNOWN_PLATFORMS.GOOGLE_CHAT,
|
|
6247
|
+
type: manifest.chatType === "group" ? "group" /* GROUP */ : "private" /* PRIVATE */,
|
|
6248
|
+
...manifest.chatType === "group" ? { groupId: manifest.chatId } : {},
|
|
6249
|
+
ownerId: owner?.platformId
|
|
6250
|
+
}
|
|
6251
|
+
};
|
|
6252
|
+
const memberMap = /* @__PURE__ */ new Map();
|
|
6253
|
+
for (const member of groupInfo.members ?? []) {
|
|
6254
|
+
const identity = normalizeIdentity(member);
|
|
6255
|
+
memberMap.set(identity.platformId, {
|
|
6256
|
+
platformId: identity.platformId,
|
|
6257
|
+
accountName: identity.name
|
|
6258
|
+
});
|
|
6259
|
+
}
|
|
6260
|
+
if (owner && !memberMap.has(owner.platformId)) {
|
|
6261
|
+
memberMap.set(owner.platformId, {
|
|
6262
|
+
platformId: owner.platformId,
|
|
6263
|
+
accountName: owner.name
|
|
6264
|
+
});
|
|
6265
|
+
}
|
|
6266
|
+
yield { type: "members", data: Array.from(memberMap.values()) };
|
|
6267
|
+
const readStream = fs16.createReadStream(messagesPath, { encoding: "utf8" });
|
|
6268
|
+
let bytesRead = 0;
|
|
6269
|
+
let messagesProcessed = 0;
|
|
6270
|
+
readStream.on("data", (chunk) => {
|
|
6271
|
+
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
6272
|
+
});
|
|
6273
|
+
const pipeline2 = chain8([readStream, parser9(), pick7({ filter: /^messages\.\d+$/ }), streamValues8()]);
|
|
6274
|
+
const messageBatch = [];
|
|
6275
|
+
try {
|
|
6276
|
+
for await (const item of pipeline2) {
|
|
6277
|
+
const message = item.value;
|
|
6278
|
+
const sender = normalizeIdentity(message.creator);
|
|
6279
|
+
messageBatch.push({
|
|
6280
|
+
platformMessageId: message.message_id ? String(message.message_id) : void 0,
|
|
6281
|
+
senderPlatformId: sender.platformId,
|
|
6282
|
+
senderAccountName: sender.name,
|
|
6283
|
+
timestamp: parseGoogleChatDate(message.created_date ?? message.updated_date ?? "") ?? Number.NaN,
|
|
6284
|
+
type: detectMessageType5(message),
|
|
6285
|
+
content: buildMessageContent(message)
|
|
6286
|
+
});
|
|
6287
|
+
messagesProcessed++;
|
|
6288
|
+
if (messageBatch.length >= batchSize) {
|
|
6289
|
+
yield { type: "messages", data: messageBatch.splice(0) };
|
|
6290
|
+
const progress = createProgress("parsing", bytesRead, totalBytes, messagesProcessed, "");
|
|
6291
|
+
yield { type: "progress", data: progress };
|
|
6292
|
+
onProgress?.(progress);
|
|
6293
|
+
}
|
|
6294
|
+
}
|
|
6295
|
+
} catch (error) {
|
|
6296
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6297
|
+
onLog?.("error", `Failed to parse Google Chat messages: ${message}`);
|
|
6298
|
+
yield { type: "error", data: new Error(`Failed to parse Google Chat messages: ${message}`) };
|
|
6299
|
+
return;
|
|
6300
|
+
}
|
|
6301
|
+
if (messageBatch.length > 0) {
|
|
6302
|
+
yield { type: "messages", data: messageBatch };
|
|
6303
|
+
}
|
|
6304
|
+
const doneProgress = createProgress("done", totalBytes, totalBytes, messagesProcessed, "");
|
|
6305
|
+
yield { type: "progress", data: doneProgress };
|
|
6306
|
+
onProgress?.(doneProgress);
|
|
6307
|
+
yield { type: "done", data: { messageCount: messagesProcessed, memberCount: memberMap.size } };
|
|
6308
|
+
}
|
|
6309
|
+
var parser_12 = {
|
|
6310
|
+
feature: feature13,
|
|
6311
|
+
parse: parseGoogleChat
|
|
6312
|
+
};
|
|
6313
|
+
var module_13 = {
|
|
6314
|
+
feature: feature13,
|
|
6315
|
+
parser: parser_12
|
|
6316
|
+
};
|
|
6317
|
+
var google_chat_takeout_default = module_13;
|
|
6318
|
+
|
|
6319
|
+
// ../../packages/parser/src/formats/line-native-txt.ts
|
|
6320
|
+
import * as fs17 from "fs";
|
|
6321
|
+
import * as path13 from "path";
|
|
6322
|
+
var feature14 = {
|
|
4737
6323
|
id: "line-native-txt",
|
|
4738
6324
|
name: "LINE \u5B98\u65B9\u5BFC\u51FA TXT",
|
|
4739
6325
|
platform: KNOWN_PLATFORMS.LINE,
|
|
@@ -4760,7 +6346,7 @@ var feature13 = {
|
|
|
4760
6346
|
}
|
|
4761
6347
|
};
|
|
4762
6348
|
function extractNameFromFilePath8(filePath) {
|
|
4763
|
-
const basename11 =
|
|
6349
|
+
const basename11 = path13.basename(filePath, ".txt");
|
|
4764
6350
|
const name = basename11.replace(/^\[LINE\]\s*/i, "").trim();
|
|
4765
6351
|
return name || "\u672A\u77E5\u804A\u5929";
|
|
4766
6352
|
}
|
|
@@ -4882,7 +6468,7 @@ var SPECIAL_MESSAGE_TYPES = {
|
|
|
4882
6468
|
"[\u30CE\u30FC\u30C8]": 0 /* TEXT */
|
|
4883
6469
|
// JA
|
|
4884
6470
|
};
|
|
4885
|
-
function
|
|
6471
|
+
function detectMessageType6(content) {
|
|
4886
6472
|
for (const [pattern, type] of Object.entries(SPECIAL_MESSAGE_TYPES)) {
|
|
4887
6473
|
if (content === pattern || content.startsWith(pattern)) {
|
|
4888
6474
|
return type;
|
|
@@ -4932,15 +6518,15 @@ function detectMessageType5(content) {
|
|
|
4932
6518
|
}
|
|
4933
6519
|
return 0 /* TEXT */;
|
|
4934
6520
|
}
|
|
4935
|
-
async function* parseLINE(
|
|
4936
|
-
const { filePath, batchSize = 5e3, onProgress, onLog } =
|
|
6521
|
+
async function* parseLINE(options2) {
|
|
6522
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
4937
6523
|
const totalBytes = getFileSize(filePath);
|
|
4938
6524
|
let messagesProcessed = 0;
|
|
4939
6525
|
const initialProgress = createProgress("parsing", 0, totalBytes, 0, "");
|
|
4940
6526
|
yield { type: "progress", data: initialProgress };
|
|
4941
6527
|
onProgress?.(initialProgress);
|
|
4942
6528
|
onLog?.("info", `\u5F00\u59CB\u89E3\u6790 LINE \u5BFC\u51FA\u6587\u4EF6\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
4943
|
-
const content =
|
|
6529
|
+
const content = fs17.readFileSync(filePath, "utf-8");
|
|
4944
6530
|
const lines = content.split("\n").map((line) => line.replace(/\r$/, ""));
|
|
4945
6531
|
let currentDate = null;
|
|
4946
6532
|
let chatName = extractNameFromFilePath8(filePath);
|
|
@@ -5033,7 +6619,7 @@ async function* parseLINE(options) {
|
|
|
5033
6619
|
now.setHours(hours, minutes, 0, 0);
|
|
5034
6620
|
timestamp = Math.floor(now.getTime() / 1e3);
|
|
5035
6621
|
}
|
|
5036
|
-
const msgType =
|
|
6622
|
+
const msgType = detectMessageType6(content2);
|
|
5037
6623
|
if (!memberMap.has(sender)) {
|
|
5038
6624
|
memberMap.set(sender, {
|
|
5039
6625
|
platformId: sender,
|
|
@@ -5141,15 +6727,15 @@ async function* parseLINE(options) {
|
|
|
5141
6727
|
data: { messageCount: messagesProcessed, memberCount }
|
|
5142
6728
|
};
|
|
5143
6729
|
}
|
|
5144
|
-
var
|
|
5145
|
-
feature:
|
|
6730
|
+
var parser_13 = {
|
|
6731
|
+
feature: feature14,
|
|
5146
6732
|
parse: parseLINE
|
|
5147
6733
|
};
|
|
5148
|
-
var
|
|
5149
|
-
feature:
|
|
5150
|
-
parser:
|
|
6734
|
+
var module_14 = {
|
|
6735
|
+
feature: feature14,
|
|
6736
|
+
parser: parser_13
|
|
5151
6737
|
};
|
|
5152
|
-
var line_native_txt_default =
|
|
6738
|
+
var line_native_txt_default = module_14;
|
|
5153
6739
|
|
|
5154
6740
|
// ../../packages/parser/src/formats/index.ts
|
|
5155
6741
|
var formats = [
|
|
@@ -5167,6 +6753,8 @@ var formats = [
|
|
|
5167
6753
|
// 优先级 22 - Telegram 官方全量导出 JSON
|
|
5168
6754
|
telegram_native_single_default,
|
|
5169
6755
|
// 优先级 23 - Telegram 单聊天导出 JSON
|
|
6756
|
+
google_chat_takeout_default,
|
|
6757
|
+
// 优先级 24 - Google Chat Takeout 内部 manifest
|
|
5170
6758
|
instagram_native_default,
|
|
5171
6759
|
// 优先级 25 - Instagram 官方导出
|
|
5172
6760
|
whatsapp_native_txt_default,
|
|
@@ -5198,22 +6786,22 @@ function getFormatFeatureById(formatId) {
|
|
|
5198
6786
|
return all.find((f) => f.id === formatId) ?? null;
|
|
5199
6787
|
}
|
|
5200
6788
|
function getPreprocessor(filePath) {
|
|
5201
|
-
const
|
|
5202
|
-
if (!
|
|
5203
|
-
const module = formats.find((m) => m.feature.id ===
|
|
6789
|
+
const feature15 = sniffer.sniff(filePath);
|
|
6790
|
+
if (!feature15) return null;
|
|
6791
|
+
const module = formats.find((m) => m.feature.id === feature15.id);
|
|
5204
6792
|
return module?.preprocessor || null;
|
|
5205
6793
|
}
|
|
5206
6794
|
async function scanMultiChatFile(filePath) {
|
|
5207
|
-
const
|
|
5208
|
-
if (!
|
|
6795
|
+
const feature15 = sniffer.sniff(filePath);
|
|
6796
|
+
if (!feature15) {
|
|
5209
6797
|
throw new Error(`\u65E0\u6CD5\u8BC6\u522B\u6587\u4EF6\u683C\u5F0F: ${filePath}`);
|
|
5210
6798
|
}
|
|
5211
|
-
if (!
|
|
5212
|
-
throw new Error(`\u683C\u5F0F "${
|
|
6799
|
+
if (!feature15.multiChat) {
|
|
6800
|
+
throw new Error(`\u683C\u5F0F "${feature15.name}" \u4E0D\u662F\u591A\u804A\u5929\u683C\u5F0F`);
|
|
5213
6801
|
}
|
|
5214
|
-
const module = formats.find((m) => m.feature.id ===
|
|
6802
|
+
const module = formats.find((m) => m.feature.id === feature15.id);
|
|
5215
6803
|
if (!module?.scanChats) {
|
|
5216
|
-
throw new Error(`\u683C\u5F0F "${
|
|
6804
|
+
throw new Error(`\u683C\u5F0F "${feature15.name}" \u58F0\u660E\u4E86 multiChat \u4F46\u672A\u5B9E\u73B0 scanChats`);
|
|
5217
6805
|
}
|
|
5218
6806
|
return module.scanChats(filePath);
|
|
5219
6807
|
}
|
|
@@ -5223,35 +6811,35 @@ function needsPreprocess(filePath) {
|
|
|
5223
6811
|
const fileSize = getFileSize(filePath);
|
|
5224
6812
|
return preprocessor.needsPreprocess(filePath, fileSize);
|
|
5225
6813
|
}
|
|
5226
|
-
async function* parseFile(
|
|
5227
|
-
const
|
|
5228
|
-
if (!
|
|
5229
|
-
yield { type: "error", data: new Error(`\u65E0\u6CD5\u8BC6\u522B\u6587\u4EF6\u683C\u5F0F: ${
|
|
6814
|
+
async function* parseFile(options2) {
|
|
6815
|
+
const parser11 = sniffer.getParser(options2.filePath);
|
|
6816
|
+
if (!parser11) {
|
|
6817
|
+
yield { type: "error", data: new Error(`\u65E0\u6CD5\u8BC6\u522B\u6587\u4EF6\u683C\u5F0F: ${options2.filePath}`) };
|
|
5230
6818
|
return;
|
|
5231
6819
|
}
|
|
5232
|
-
console.log(`[Parser V2] Using parser: ${
|
|
5233
|
-
yield*
|
|
6820
|
+
console.log(`[Parser V2] Using parser: ${parser11.feature.name}`);
|
|
6821
|
+
yield* parser11.parse(options2);
|
|
5234
6822
|
}
|
|
5235
|
-
async function* parseFileWithFormat(formatId,
|
|
5236
|
-
const
|
|
5237
|
-
if (!
|
|
6823
|
+
async function* parseFileWithFormat(formatId, options2) {
|
|
6824
|
+
const parser11 = sniffer.getParserById(formatId);
|
|
6825
|
+
if (!parser11) {
|
|
5238
6826
|
yield { type: "error", data: new Error(`\u672A\u77E5\u7684\u683C\u5F0F ID: ${formatId}`) };
|
|
5239
6827
|
return;
|
|
5240
6828
|
}
|
|
5241
|
-
console.log(`[Parser V2] Using parser (explicit): ${
|
|
5242
|
-
yield*
|
|
6829
|
+
console.log(`[Parser V2] Using parser (explicit): ${parser11.feature.name}`);
|
|
6830
|
+
yield* parser11.parse(options2);
|
|
5243
6831
|
}
|
|
5244
6832
|
function findEntryFileInDirectory(dirPath, maxDepth = 1) {
|
|
5245
6833
|
function walk(current, depth) {
|
|
5246
6834
|
if (depth > maxDepth) return null;
|
|
5247
6835
|
let entries;
|
|
5248
6836
|
try {
|
|
5249
|
-
entries =
|
|
6837
|
+
entries = fs18.readdirSync(current, { withFileTypes: true });
|
|
5250
6838
|
} catch {
|
|
5251
6839
|
return null;
|
|
5252
6840
|
}
|
|
5253
6841
|
for (const entry of entries) {
|
|
5254
|
-
const full =
|
|
6842
|
+
const full = path14.join(current, entry.name);
|
|
5255
6843
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
5256
6844
|
const format = detectFormat(full);
|
|
5257
6845
|
if (format) return full;
|
|
@@ -5259,7 +6847,7 @@ function findEntryFileInDirectory(dirPath, maxDepth = 1) {
|
|
|
5259
6847
|
}
|
|
5260
6848
|
for (const entry of entries) {
|
|
5261
6849
|
if (entry.isDirectory()) {
|
|
5262
|
-
const found = walk(
|
|
6850
|
+
const found = walk(path14.join(current, entry.name), depth + 1);
|
|
5263
6851
|
if (found) return found;
|
|
5264
6852
|
}
|
|
5265
6853
|
}
|
|
@@ -5291,7 +6879,7 @@ async function streamParseFile(filePath, callbacks, formatId) {
|
|
|
5291
6879
|
}
|
|
5292
6880
|
|
|
5293
6881
|
// ../../packages/node-runtime/src/import/streaming-importer.ts
|
|
5294
|
-
import * as
|
|
6882
|
+
import * as fs19 from "fs";
|
|
5295
6883
|
var BATCH_COMMIT_SIZE = 5e4;
|
|
5296
6884
|
var CHECKPOINT_INTERVAL = 2e5;
|
|
5297
6885
|
function defaultGenerateSessionId() {
|
|
@@ -5302,11 +6890,11 @@ function defaultGenerateSessionId() {
|
|
|
5302
6890
|
async function streamingImport(filePath, deps, formatOptions, externalSessionId) {
|
|
5303
6891
|
if (formatOptions?.formatId) {
|
|
5304
6892
|
const formatId = formatOptions.formatId;
|
|
5305
|
-
const
|
|
5306
|
-
if (!
|
|
6893
|
+
const feature15 = getFormatFeatureById(formatId);
|
|
6894
|
+
if (!feature15) {
|
|
5307
6895
|
return { success: false, error: "error.unknown_format_id" };
|
|
5308
6896
|
}
|
|
5309
|
-
return streamImportSingle(filePath, deps,
|
|
6897
|
+
return streamImportSingle(filePath, deps, feature15, formatOptions, externalSessionId);
|
|
5310
6898
|
}
|
|
5311
6899
|
const candidates = detectAllFormats(filePath);
|
|
5312
6900
|
if (candidates.length === 0) {
|
|
@@ -5741,7 +7329,7 @@ async function streamParseFileInfo(filePath, deps) {
|
|
|
5741
7329
|
if (!formatFeature) {
|
|
5742
7330
|
throw new Error("Unrecognized file format");
|
|
5743
7331
|
}
|
|
5744
|
-
const fileSize =
|
|
7332
|
+
const fileSize = fs19.statSync(filePath).size;
|
|
5745
7333
|
deps.onProgress({
|
|
5746
7334
|
stage: "parsing",
|
|
5747
7335
|
bytesRead: 0,
|
|
@@ -5830,7 +7418,7 @@ async function streamParseFileInfo(filePath, deps) {
|
|
|
5830
7418
|
}
|
|
5831
7419
|
db.close();
|
|
5832
7420
|
try {
|
|
5833
|
-
if (
|
|
7421
|
+
if (fs19.existsSync(tempDbPath)) fs19.unlinkSync(tempDbPath);
|
|
5834
7422
|
} catch {
|
|
5835
7423
|
}
|
|
5836
7424
|
throw error;
|
|
@@ -5963,7 +7551,7 @@ async function analyzeIncrementalImport(sessionId, filePath, deps) {
|
|
|
5963
7551
|
});
|
|
5964
7552
|
return { newMessageCount, duplicateCount, totalInFile };
|
|
5965
7553
|
}
|
|
5966
|
-
async function incrementalImport(sessionId, filePath, deps,
|
|
7554
|
+
async function incrementalImport(sessionId, filePath, deps, options2) {
|
|
5967
7555
|
const formatFeature = detectFormat(filePath);
|
|
5968
7556
|
if (!formatFeature) {
|
|
5969
7557
|
return { success: false, newMessageCount: 0, error: "error.unrecognized_format" };
|
|
@@ -5974,8 +7562,8 @@ async function incrementalImport(sessionId, filePath, deps, options) {
|
|
|
5974
7562
|
} catch {
|
|
5975
7563
|
return { success: false, newMessageCount: 0, error: "error.session_not_found" };
|
|
5976
7564
|
}
|
|
5977
|
-
const metaUpdateMode =
|
|
5978
|
-
const memberUpdateMode =
|
|
7565
|
+
const metaUpdateMode = options2?.metaUpdateMode ?? "patch";
|
|
7566
|
+
const memberUpdateMode = options2?.memberUpdateMode ?? "upsert";
|
|
5979
7567
|
try {
|
|
5980
7568
|
let trackError2 = function(index, reason, detail) {
|
|
5981
7569
|
errorCount2++;
|
|
@@ -6194,14 +7782,550 @@ async function incrementalImport(sessionId, filePath, deps, options) {
|
|
|
6194
7782
|
}
|
|
6195
7783
|
}
|
|
6196
7784
|
|
|
6197
|
-
// ../../packages/node-runtime/src/
|
|
7785
|
+
// ../../packages/node-runtime/src/import/archive/archive-reader.ts
|
|
7786
|
+
var import_yauzl = __toESM(require_yauzl(), 1);
|
|
6198
7787
|
import * as fs20 from "fs";
|
|
6199
|
-
import * as os2 from "os";
|
|
6200
7788
|
import * as path15 from "path";
|
|
7789
|
+
import { pipeline } from "stream/promises";
|
|
7790
|
+
|
|
7791
|
+
// ../../packages/node-runtime/src/import/archive/errors.ts
|
|
7792
|
+
var ArchiveImportError = class extends Error {
|
|
7793
|
+
constructor(code, message, options2) {
|
|
7794
|
+
super(message, options2);
|
|
7795
|
+
this.code = code;
|
|
7796
|
+
this.name = "ArchiveImportError";
|
|
7797
|
+
}
|
|
7798
|
+
code;
|
|
7799
|
+
};
|
|
7800
|
+
|
|
7801
|
+
// ../../packages/node-runtime/src/import/archive/archive-reader.ts
|
|
7802
|
+
var DEFAULT_MAX_ENTRIES = 1e5;
|
|
7803
|
+
var DEFAULT_MAX_ENTRY_BYTES = 20 * 1024 * 1024 * 1024;
|
|
7804
|
+
var DEFAULT_MAX_COMPRESSION_RATIO = 1e4;
|
|
7805
|
+
function validateArchiveEntryName(fileName) {
|
|
7806
|
+
if (fileName.startsWith("/") || /^[A-Za-z]:\//.test(fileName) || fileName.includes("\\") || fileName.split("/").includes("..")) {
|
|
7807
|
+
throw new ArchiveImportError("error.archive_unsafe_path", `Unsafe archive entry path: ${fileName}`);
|
|
7808
|
+
}
|
|
7809
|
+
}
|
|
7810
|
+
function mapArchiveError(error) {
|
|
7811
|
+
if (error instanceof ArchiveImportError) return error;
|
|
7812
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7813
|
+
return new ArchiveImportError("error.archive_corrupt", `Invalid ZIP archive: ${message}`, {
|
|
7814
|
+
cause: error
|
|
7815
|
+
});
|
|
7816
|
+
}
|
|
7817
|
+
function toSummary(entry) {
|
|
7818
|
+
return {
|
|
7819
|
+
name: entry.fileName,
|
|
7820
|
+
compressedSize: entry.compressedSize,
|
|
7821
|
+
uncompressedSize: entry.uncompressedSize,
|
|
7822
|
+
compressionMethod: entry.compressionMethod,
|
|
7823
|
+
isDirectory: entry.fileName.endsWith("/")
|
|
7824
|
+
};
|
|
7825
|
+
}
|
|
7826
|
+
function validateEntry(entry, options2) {
|
|
7827
|
+
validateArchiveEntryName(entry.fileName);
|
|
7828
|
+
if (entry.isEncrypted()) {
|
|
7829
|
+
throw new ArchiveImportError("error.archive_encrypted", `Encrypted ZIP entry is not supported: ${entry.fileName}`);
|
|
7830
|
+
}
|
|
7831
|
+
if (!entry.canDecodeFileData() || entry.compressionMethod !== 0 && entry.compressionMethod !== 8) {
|
|
7832
|
+
throw new ArchiveImportError(
|
|
7833
|
+
"error.archive_unsupported",
|
|
7834
|
+
`Unsupported ZIP compression method for entry: ${entry.fileName}`
|
|
7835
|
+
);
|
|
7836
|
+
}
|
|
7837
|
+
if (entry.uncompressedSize > options2.maxEntryBytes) {
|
|
7838
|
+
throw new ArchiveImportError("error.archive_limit_exceeded", `ZIP entry exceeds the size limit: ${entry.fileName}`);
|
|
7839
|
+
}
|
|
7840
|
+
if (entry.uncompressedSize > 0) {
|
|
7841
|
+
const ratio = entry.compressedSize === 0 ? Number.POSITIVE_INFINITY : entry.uncompressedSize / entry.compressedSize;
|
|
7842
|
+
if (ratio > options2.maxCompressionRatio) {
|
|
7843
|
+
throw new ArchiveImportError(
|
|
7844
|
+
"error.archive_limit_exceeded",
|
|
7845
|
+
`ZIP entry exceeds the compression ratio limit: ${entry.fileName}`
|
|
7846
|
+
);
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7849
|
+
}
|
|
7850
|
+
var ZipArchiveReader = class {
|
|
7851
|
+
constructor(archivePath, options2 = {}) {
|
|
7852
|
+
this.archivePath = archivePath;
|
|
7853
|
+
this.options = {
|
|
7854
|
+
maxEntries: options2.maxEntries ?? DEFAULT_MAX_ENTRIES,
|
|
7855
|
+
maxEntryBytes: options2.maxEntryBytes ?? DEFAULT_MAX_ENTRY_BYTES,
|
|
7856
|
+
maxCompressionRatio: options2.maxCompressionRatio ?? DEFAULT_MAX_COMPRESSION_RATIO
|
|
7857
|
+
};
|
|
7858
|
+
}
|
|
7859
|
+
archivePath;
|
|
7860
|
+
options;
|
|
7861
|
+
async open() {
|
|
7862
|
+
try {
|
|
7863
|
+
return await (0, import_yauzl.openPromise)(this.archivePath, {
|
|
7864
|
+
autoClose: true,
|
|
7865
|
+
decodeStrings: true,
|
|
7866
|
+
validateEntrySizes: true,
|
|
7867
|
+
strictFileNames: true
|
|
7868
|
+
});
|
|
7869
|
+
} catch (error) {
|
|
7870
|
+
throw mapArchiveError(error);
|
|
7871
|
+
}
|
|
7872
|
+
}
|
|
7873
|
+
async listEntries() {
|
|
7874
|
+
const entries = [];
|
|
7875
|
+
await this.visitEntries((entry) => {
|
|
7876
|
+
entries.push(entry);
|
|
7877
|
+
});
|
|
7878
|
+
return entries;
|
|
7879
|
+
}
|
|
7880
|
+
/**
|
|
7881
|
+
* 每次只推进一个 ZIP 条目;visitor 若打开流,必须等待流消费结束后返回。
|
|
7882
|
+
* 这样大 ZIP 不会同时创建大量 inflate stream。
|
|
7883
|
+
*/
|
|
7884
|
+
async visitEntries(visitor) {
|
|
7885
|
+
const zipFile = await this.open();
|
|
7886
|
+
let count = 0;
|
|
7887
|
+
try {
|
|
7888
|
+
for await (const entry of zipFile.eachEntry()) {
|
|
7889
|
+
count++;
|
|
7890
|
+
if (count > this.options.maxEntries) {
|
|
7891
|
+
throw new ArchiveImportError("error.archive_limit_exceeded", "ZIP archive contains too many entries");
|
|
7892
|
+
}
|
|
7893
|
+
validateEntry(entry, this.options);
|
|
7894
|
+
let opened = false;
|
|
7895
|
+
const openStream = async () => {
|
|
7896
|
+
if (opened) {
|
|
7897
|
+
throw new ArchiveImportError("error.archive_corrupt", `ZIP entry stream opened twice: ${entry.fileName}`);
|
|
7898
|
+
}
|
|
7899
|
+
opened = true;
|
|
7900
|
+
try {
|
|
7901
|
+
return await zipFile.openReadStreamPromise(entry);
|
|
7902
|
+
} catch (error) {
|
|
7903
|
+
throw mapArchiveError(error);
|
|
7904
|
+
}
|
|
7905
|
+
};
|
|
7906
|
+
await visitor(toSummary(entry), openStream);
|
|
7907
|
+
}
|
|
7908
|
+
} catch (error) {
|
|
7909
|
+
throw mapArchiveError(error);
|
|
7910
|
+
} finally {
|
|
7911
|
+
if (zipFile.isOpen) zipFile.close();
|
|
7912
|
+
}
|
|
7913
|
+
}
|
|
7914
|
+
async pipeEntries(targets) {
|
|
7915
|
+
const remaining = new Set(targets.keys());
|
|
7916
|
+
await this.visitEntries(async (entry, openStream) => {
|
|
7917
|
+
const destination = targets.get(entry.name);
|
|
7918
|
+
if (!destination || entry.isDirectory) return;
|
|
7919
|
+
fs20.mkdirSync(path15.dirname(destination), { recursive: true });
|
|
7920
|
+
await pipeline(await openStream(), fs20.createWriteStream(destination, { flags: "wx" }));
|
|
7921
|
+
remaining.delete(entry.name);
|
|
7922
|
+
});
|
|
7923
|
+
if (remaining.size > 0) {
|
|
7924
|
+
throw new ArchiveImportError(
|
|
7925
|
+
"error.archive_corrupt",
|
|
7926
|
+
`ZIP archive is missing expected entries: ${Array.from(remaining).join(", ")}`
|
|
7927
|
+
);
|
|
7928
|
+
}
|
|
7929
|
+
}
|
|
7930
|
+
};
|
|
7931
|
+
|
|
7932
|
+
// ../../packages/node-runtime/src/import/archive/google-chat-resolver.ts
|
|
7933
|
+
var import_stream_chain9 = __toESM(require_stream_chain(), 1);
|
|
7934
|
+
var import_stream_json9 = __toESM(require_stream_json(), 1);
|
|
7935
|
+
var import_Pick8 = __toESM(require_Pick(), 1);
|
|
7936
|
+
var import_StreamValues9 = __toESM(require_StreamValues(), 1);
|
|
7937
|
+
import * as fs21 from "fs";
|
|
7938
|
+
import * as path16 from "path";
|
|
7939
|
+
var { chain: chain9 } = import_stream_chain9.default;
|
|
7940
|
+
var { parser: parser10 } = import_stream_json9.default;
|
|
7941
|
+
var { pick: pick8 } = import_Pick8.default;
|
|
7942
|
+
var { streamValues: streamValues9 } = import_StreamValues9.default;
|
|
7943
|
+
var GROUP_FILE = /^Takeout\/Google Chat\/Groups\/((DM|Space) [^/]+)\/(group_info|messages)\.json$/;
|
|
7944
|
+
var USER_INFO_FILE = /^Takeout\/Google Chat\/Users\/[^/]+\/user_info\.json$/;
|
|
7945
|
+
var TAKEOUT_ROOT = /^Takeout\/([^/]+)\//;
|
|
7946
|
+
var MAX_METADATA_BYTES = 5 * 1024 * 1024;
|
|
7947
|
+
async function readSmallJson(stream, maxBytes = MAX_METADATA_BYTES) {
|
|
7948
|
+
const chunks = [];
|
|
7949
|
+
let total = 0;
|
|
7950
|
+
for await (const chunk of stream) {
|
|
7951
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
7952
|
+
total += buffer.length;
|
|
7953
|
+
if (total > maxBytes) {
|
|
7954
|
+
throw new ArchiveImportError("error.archive_limit_exceeded", "Google Chat metadata exceeds the size limit");
|
|
7955
|
+
}
|
|
7956
|
+
chunks.push(buffer);
|
|
7957
|
+
}
|
|
7958
|
+
try {
|
|
7959
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
7960
|
+
} catch (error) {
|
|
7961
|
+
throw new ArchiveImportError("error.archive_corrupt", "Invalid Google Chat metadata JSON", { cause: error });
|
|
7962
|
+
}
|
|
7963
|
+
}
|
|
7964
|
+
async function countMessages(stream) {
|
|
7965
|
+
const pipeline2 = chain9([stream, parser10(), pick8({ filter: /^messages\.\d+$/ }), streamValues9()]);
|
|
7966
|
+
let count = 0;
|
|
7967
|
+
try {
|
|
7968
|
+
for await (const _item of pipeline2) count++;
|
|
7969
|
+
return count;
|
|
7970
|
+
} catch (error) {
|
|
7971
|
+
throw new ArchiveImportError("error.archive_corrupt", "Invalid Google Chat messages JSON", { cause: error });
|
|
7972
|
+
}
|
|
7973
|
+
}
|
|
7974
|
+
function normalizeEmail(user) {
|
|
7975
|
+
return user?.email?.trim().toLowerCase() || null;
|
|
7976
|
+
}
|
|
7977
|
+
function deriveConversationName(draft, ownerEmail) {
|
|
7978
|
+
const groupInfo = draft.groupInfo;
|
|
7979
|
+
if (draft.kind === "Space" && groupInfo?.name?.trim()) return groupInfo.name.trim();
|
|
7980
|
+
const members = groupInfo?.members ?? [];
|
|
7981
|
+
const other = members.find((member) => {
|
|
7982
|
+
const email = normalizeEmail(member);
|
|
7983
|
+
return !ownerEmail || email !== ownerEmail;
|
|
7984
|
+
});
|
|
7985
|
+
return other?.name?.trim() || other?.email?.trim() || members[0]?.name?.trim() || draft.chatId;
|
|
7986
|
+
}
|
|
7987
|
+
var GoogleChatTakeoutResolver = class {
|
|
7988
|
+
id = "google-chat-takeout";
|
|
7989
|
+
platform = "google-chat";
|
|
7990
|
+
detect(entries) {
|
|
7991
|
+
const products = /* @__PURE__ */ new Set();
|
|
7992
|
+
const groupFiles = /* @__PURE__ */ new Map();
|
|
7993
|
+
for (const entry of entries) {
|
|
7994
|
+
const product = entry.name.match(TAKEOUT_ROOT)?.[1];
|
|
7995
|
+
if (product) products.add(product);
|
|
7996
|
+
const match = entry.name.match(GROUP_FILE);
|
|
7997
|
+
if (!match) continue;
|
|
7998
|
+
const files = groupFiles.get(match[1]) ?? /* @__PURE__ */ new Set();
|
|
7999
|
+
files.add(match[3]);
|
|
8000
|
+
groupFiles.set(match[1], files);
|
|
8001
|
+
}
|
|
8002
|
+
return products.size === 1 && products.has("Google Chat") && Array.from(groupFiles.values()).some((files) => files.has("group_info") && files.has("messages"));
|
|
8003
|
+
}
|
|
8004
|
+
/**
|
|
8005
|
+
* 扫描时按 ZIP 顺序消费必要 JSON。会话元数据和消息计数先暂存,
|
|
8006
|
+
* 等 owner 信息齐备后统一生成名称,避免依赖归档内部文件顺序。
|
|
8007
|
+
*/
|
|
8008
|
+
async scan(reader) {
|
|
8009
|
+
let ownerEmail = null;
|
|
8010
|
+
const drafts = /* @__PURE__ */ new Map();
|
|
8011
|
+
await reader.visitEntries(async (entry, openStream) => {
|
|
8012
|
+
if (USER_INFO_FILE.test(entry.name)) {
|
|
8013
|
+
const ownerInfo = await readSmallJson(await openStream());
|
|
8014
|
+
ownerEmail = normalizeEmail(ownerInfo.user);
|
|
8015
|
+
return;
|
|
8016
|
+
}
|
|
8017
|
+
const match = entry.name.match(GROUP_FILE);
|
|
8018
|
+
if (!match) return;
|
|
8019
|
+
const chatId = `Groups/${match[1]}`;
|
|
8020
|
+
const draft = drafts.get(chatId) ?? {
|
|
8021
|
+
chatId,
|
|
8022
|
+
kind: match[2]
|
|
8023
|
+
};
|
|
8024
|
+
if (match[3] === "group_info") {
|
|
8025
|
+
draft.groupInfoEntry = entry.name;
|
|
8026
|
+
draft.groupInfo = await readSmallJson(await openStream());
|
|
8027
|
+
} else {
|
|
8028
|
+
draft.messagesEntry = entry.name;
|
|
8029
|
+
draft.messageCount = await countMessages(await openStream());
|
|
8030
|
+
}
|
|
8031
|
+
drafts.set(chatId, draft);
|
|
8032
|
+
});
|
|
8033
|
+
if (drafts.size === 0) {
|
|
8034
|
+
throw new ArchiveImportError(
|
|
8035
|
+
"error.google_chat_structure_not_found",
|
|
8036
|
+
"Google Chat conversation structure was not found"
|
|
8037
|
+
);
|
|
8038
|
+
}
|
|
8039
|
+
return Array.from(drafts.values()).map((draft) => {
|
|
8040
|
+
if (!draft.groupInfoEntry || !draft.messagesEntry || !draft.groupInfo || draft.messageCount === void 0) {
|
|
8041
|
+
throw new ArchiveImportError(
|
|
8042
|
+
"error.google_chat_conversation_incomplete",
|
|
8043
|
+
`Google Chat conversation is missing required files: ${draft.chatId}`
|
|
8044
|
+
);
|
|
8045
|
+
}
|
|
8046
|
+
return {
|
|
8047
|
+
chatId: draft.chatId,
|
|
8048
|
+
name: deriveConversationName(draft, ownerEmail),
|
|
8049
|
+
type: draft.kind === "Space" ? "group" : "private",
|
|
8050
|
+
messageCount: draft.messageCount,
|
|
8051
|
+
memberCount: draft.groupInfo.members?.length ?? 0
|
|
8052
|
+
};
|
|
8053
|
+
}).sort((a, b) => a.chatId.localeCompare(b.chatId));
|
|
8054
|
+
}
|
|
8055
|
+
async materialize(reader, chat, targetDir) {
|
|
8056
|
+
const entries = await reader.listEntries();
|
|
8057
|
+
const groupPrefix = `Takeout/Google Chat/${chat.chatId}/`;
|
|
8058
|
+
const userInfoEntry = entries.find((entry) => USER_INFO_FILE.test(entry.name))?.name;
|
|
8059
|
+
const groupInfoEntry = `${groupPrefix}group_info.json`;
|
|
8060
|
+
const messagesEntry = `${groupPrefix}messages.json`;
|
|
8061
|
+
if (!userInfoEntry || !entries.some((entry) => entry.name === groupInfoEntry) || !entries.some((entry) => entry.name === messagesEntry)) {
|
|
8062
|
+
throw new ArchiveImportError(
|
|
8063
|
+
"error.google_chat_conversation_incomplete",
|
|
8064
|
+
`Google Chat conversation is missing required files: ${chat.chatId}`
|
|
8065
|
+
);
|
|
8066
|
+
}
|
|
8067
|
+
fs21.mkdirSync(targetDir, { recursive: true });
|
|
8068
|
+
await reader.pipeEntries(
|
|
8069
|
+
/* @__PURE__ */ new Map([
|
|
8070
|
+
[userInfoEntry, path16.join(targetDir, "user_info.json")],
|
|
8071
|
+
[groupInfoEntry, path16.join(targetDir, "group_info.json")],
|
|
8072
|
+
[messagesEntry, path16.join(targetDir, "messages.json")]
|
|
8073
|
+
])
|
|
8074
|
+
);
|
|
8075
|
+
const manifestPath = path16.join(targetDir, "google-chat-import.json");
|
|
8076
|
+
fs21.writeFileSync(
|
|
8077
|
+
manifestPath,
|
|
8078
|
+
JSON.stringify(
|
|
8079
|
+
{
|
|
8080
|
+
format: "chatlab-google-chat-takeout",
|
|
8081
|
+
version: 1,
|
|
8082
|
+
chatId: chat.chatId,
|
|
8083
|
+
chatType: chat.type,
|
|
8084
|
+
chatName: chat.name,
|
|
8085
|
+
userInfoFile: "user_info.json",
|
|
8086
|
+
groupInfoFile: "group_info.json",
|
|
8087
|
+
messagesFile: "messages.json"
|
|
8088
|
+
},
|
|
8089
|
+
null,
|
|
8090
|
+
2
|
|
8091
|
+
),
|
|
8092
|
+
{ encoding: "utf8", flag: "wx" }
|
|
8093
|
+
);
|
|
8094
|
+
return { manifestPath };
|
|
8095
|
+
}
|
|
8096
|
+
};
|
|
8097
|
+
|
|
8098
|
+
// ../../packages/node-runtime/src/import/archive/source-manager.ts
|
|
8099
|
+
import * as fs22 from "fs";
|
|
8100
|
+
import * as path17 from "path";
|
|
8101
|
+
import { randomUUID } from "crypto";
|
|
8102
|
+
var DEFAULT_TTL_MS = 30 * 60 * 1e3;
|
|
8103
|
+
var ArchiveImportSourceManager = class {
|
|
8104
|
+
records = /* @__PURE__ */ new Map();
|
|
8105
|
+
expiredSourceIds = /* @__PURE__ */ new Set();
|
|
8106
|
+
tempRoot;
|
|
8107
|
+
ttlMs;
|
|
8108
|
+
now;
|
|
8109
|
+
resolvers;
|
|
8110
|
+
constructor(options2 = {}) {
|
|
8111
|
+
this.tempRoot = options2.tempRoot ?? path17.join(process.cwd(), ".chatlab-import-sources");
|
|
8112
|
+
this.ttlMs = options2.ttlMs ?? DEFAULT_TTL_MS;
|
|
8113
|
+
this.now = options2.now ?? Date.now;
|
|
8114
|
+
this.resolvers = options2.resolvers ?? [new GoogleChatTakeoutResolver()];
|
|
8115
|
+
fs22.mkdirSync(this.tempRoot, { recursive: true });
|
|
8116
|
+
}
|
|
8117
|
+
prepareLocalArchive(archivePath) {
|
|
8118
|
+
return this.prepareArchive(archivePath, false);
|
|
8119
|
+
}
|
|
8120
|
+
prepareOwnedArchive(archivePath) {
|
|
8121
|
+
return this.prepareArchive(archivePath, true);
|
|
8122
|
+
}
|
|
8123
|
+
async prepareArchive(archivePath, ownsArchive) {
|
|
8124
|
+
await this.cleanupExpired();
|
|
8125
|
+
const reader = new ZipArchiveReader(archivePath);
|
|
8126
|
+
try {
|
|
8127
|
+
const entries = await reader.listEntries();
|
|
8128
|
+
const matches = this.resolvers.filter((resolver2) => resolver2.detect(entries));
|
|
8129
|
+
if (matches.length !== 1) {
|
|
8130
|
+
throw new ArchiveImportError(
|
|
8131
|
+
"error.archive_unsupported",
|
|
8132
|
+
matches.length === 0 ? "Unsupported archive format" : "Archive matches multiple import formats"
|
|
8133
|
+
);
|
|
8134
|
+
}
|
|
8135
|
+
const resolver = matches[0];
|
|
8136
|
+
const chats = await resolver.scan(reader);
|
|
8137
|
+
const createdAt = this.now();
|
|
8138
|
+
const sourceId = randomUUID();
|
|
8139
|
+
const descriptor = {
|
|
8140
|
+
sourceId,
|
|
8141
|
+
formatId: resolver.id,
|
|
8142
|
+
platform: resolver.platform,
|
|
8143
|
+
chats,
|
|
8144
|
+
expiresAt: createdAt + this.ttlMs
|
|
8145
|
+
};
|
|
8146
|
+
this.records.set(sourceId, {
|
|
8147
|
+
descriptor,
|
|
8148
|
+
archivePath,
|
|
8149
|
+
ownsArchive,
|
|
8150
|
+
resolver,
|
|
8151
|
+
lastAccessAt: createdAt
|
|
8152
|
+
});
|
|
8153
|
+
return descriptor;
|
|
8154
|
+
} catch (error) {
|
|
8155
|
+
if (ownsArchive) this.removePath(archivePath);
|
|
8156
|
+
throw error;
|
|
8157
|
+
}
|
|
8158
|
+
}
|
|
8159
|
+
/**
|
|
8160
|
+
* selected chat 的 JSON 物化目录只在 handler 生命周期内存在。
|
|
8161
|
+
* 无论数据库导入成功、失败还是抛异常,finally 都会删除它。
|
|
8162
|
+
*/
|
|
8163
|
+
async withMaterializedChat(sourceId, chatId, handler) {
|
|
8164
|
+
const record = await this.getActiveRecord(sourceId);
|
|
8165
|
+
const chat = record.descriptor.chats.find((item) => item.chatId === chatId);
|
|
8166
|
+
if (!chat) {
|
|
8167
|
+
throw new ArchiveImportError(
|
|
8168
|
+
"error.google_chat_conversation_incomplete",
|
|
8169
|
+
`Archive conversation was not found: ${chatId}`
|
|
8170
|
+
);
|
|
8171
|
+
}
|
|
8172
|
+
const materializedDir = fs22.mkdtempSync(path17.join(this.tempRoot, `materialized-${sourceId}-`));
|
|
8173
|
+
try {
|
|
8174
|
+
const reader = new ZipArchiveReader(record.archivePath);
|
|
8175
|
+
const materialized = await record.resolver.materialize(reader, chat, materializedDir);
|
|
8176
|
+
return await handler(materialized.manifestPath);
|
|
8177
|
+
} finally {
|
|
8178
|
+
this.removePath(materializedDir);
|
|
8179
|
+
}
|
|
8180
|
+
}
|
|
8181
|
+
async release(sourceId) {
|
|
8182
|
+
const record = this.records.get(sourceId);
|
|
8183
|
+
if (!record) return;
|
|
8184
|
+
this.records.delete(sourceId);
|
|
8185
|
+
if (record.ownsArchive) this.removePath(record.archivePath);
|
|
8186
|
+
}
|
|
8187
|
+
async cleanupExpired(now = this.now()) {
|
|
8188
|
+
let removed = 0;
|
|
8189
|
+
for (const [sourceId, record] of this.records) {
|
|
8190
|
+
if (now - record.lastAccessAt < this.ttlMs) continue;
|
|
8191
|
+
this.records.delete(sourceId);
|
|
8192
|
+
this.expiredSourceIds.add(sourceId);
|
|
8193
|
+
if (record.ownsArchive) this.removePath(record.archivePath);
|
|
8194
|
+
removed++;
|
|
8195
|
+
}
|
|
8196
|
+
return removed;
|
|
8197
|
+
}
|
|
8198
|
+
async close() {
|
|
8199
|
+
for (const sourceId of Array.from(this.records.keys())) {
|
|
8200
|
+
await this.release(sourceId);
|
|
8201
|
+
}
|
|
8202
|
+
this.removePath(this.tempRoot);
|
|
8203
|
+
}
|
|
8204
|
+
async getActiveRecord(sourceId) {
|
|
8205
|
+
const record = this.records.get(sourceId);
|
|
8206
|
+
if (!record) {
|
|
8207
|
+
const code = this.expiredSourceIds.has(sourceId) ? "error.import_source_expired" : "error.import_source_not_found";
|
|
8208
|
+
throw new ArchiveImportError(code, `Archive import source is unavailable: ${sourceId}`);
|
|
8209
|
+
}
|
|
8210
|
+
const now = this.now();
|
|
8211
|
+
if (now - record.lastAccessAt >= this.ttlMs) {
|
|
8212
|
+
this.records.delete(sourceId);
|
|
8213
|
+
this.expiredSourceIds.add(sourceId);
|
|
8214
|
+
if (record.ownsArchive) this.removePath(record.archivePath);
|
|
8215
|
+
throw new ArchiveImportError("error.import_source_expired", `Archive import source expired: ${sourceId}`);
|
|
8216
|
+
}
|
|
8217
|
+
record.lastAccessAt = now;
|
|
8218
|
+
record.descriptor.expiresAt = now + this.ttlMs;
|
|
8219
|
+
return record;
|
|
8220
|
+
}
|
|
8221
|
+
removePath(targetPath) {
|
|
8222
|
+
try {
|
|
8223
|
+
fs22.rmSync(targetPath, { recursive: true, force: true });
|
|
8224
|
+
} catch {
|
|
8225
|
+
}
|
|
8226
|
+
}
|
|
8227
|
+
};
|
|
8228
|
+
|
|
8229
|
+
// ../../packages/node-runtime/src/logging/app-logger.ts
|
|
8230
|
+
import * as fs23 from "fs";
|
|
8231
|
+
import * as path18 from "path";
|
|
8232
|
+
var LEVEL_ORDER = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
|
|
8233
|
+
var MAX_SIZE_BYTES = 10 * 1024 * 1024;
|
|
8234
|
+
var AppLogger = class {
|
|
8235
|
+
logFile;
|
|
8236
|
+
oldLogFile;
|
|
8237
|
+
threshold;
|
|
8238
|
+
constructor(logsDir) {
|
|
8239
|
+
this.logFile = path18.join(logsDir, "app.log");
|
|
8240
|
+
this.oldLogFile = path18.join(logsDir, "app.old.log");
|
|
8241
|
+
this.threshold = resolveThreshold();
|
|
8242
|
+
}
|
|
8243
|
+
debug(scope, message, data) {
|
|
8244
|
+
this.write("DEBUG", scope, message, data);
|
|
8245
|
+
}
|
|
8246
|
+
info(scope, message, data) {
|
|
8247
|
+
this.write("INFO", scope, message, data);
|
|
8248
|
+
}
|
|
8249
|
+
warn(scope, message, data) {
|
|
8250
|
+
this.write("WARN", scope, message, data);
|
|
8251
|
+
}
|
|
8252
|
+
/** `data` may be an Error; its name/message/stack are extracted automatically. */
|
|
8253
|
+
error(scope, message, data) {
|
|
8254
|
+
this.write("ERROR", scope, message, data);
|
|
8255
|
+
}
|
|
8256
|
+
getLogPath() {
|
|
8257
|
+
return this.logFile;
|
|
8258
|
+
}
|
|
8259
|
+
write(level, scope, message, data) {
|
|
8260
|
+
if (LEVEL_ORDER[level] < LEVEL_ORDER[this.threshold]) return;
|
|
8261
|
+
let line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${level}] [${scope}] ${message}`;
|
|
8262
|
+
try {
|
|
8263
|
+
const tail = formatData(data);
|
|
8264
|
+
if (tail) line += `
|
|
8265
|
+
${tail}`;
|
|
8266
|
+
line += "\n";
|
|
8267
|
+
ensureDir2(path18.dirname(this.logFile));
|
|
8268
|
+
this.rotateIfNeeded();
|
|
8269
|
+
fs23.appendFileSync(this.logFile, line, "utf-8");
|
|
8270
|
+
} catch (err) {
|
|
8271
|
+
console.error("[AppLogger] Failed to write log:", err);
|
|
8272
|
+
}
|
|
8273
|
+
}
|
|
8274
|
+
// ponytail: rename-based rotation, atomic, no rewrite, ~20MB total ceiling
|
|
8275
|
+
rotateIfNeeded() {
|
|
8276
|
+
let size = 0;
|
|
8277
|
+
try {
|
|
8278
|
+
size = fs23.statSync(this.logFile).size;
|
|
8279
|
+
} catch {
|
|
8280
|
+
return;
|
|
8281
|
+
}
|
|
8282
|
+
if (size < MAX_SIZE_BYTES) return;
|
|
8283
|
+
fs23.renameSync(this.logFile, this.oldLogFile);
|
|
8284
|
+
}
|
|
8285
|
+
};
|
|
8286
|
+
function resolveThreshold() {
|
|
8287
|
+
const raw = (process.env.CHATLAB_LOG_LEVEL || "").toUpperCase();
|
|
8288
|
+
if (raw === "DEBUG" || raw === "INFO" || raw === "WARN" || raw === "ERROR") return raw;
|
|
8289
|
+
return "INFO";
|
|
8290
|
+
}
|
|
8291
|
+
function formatData(data) {
|
|
8292
|
+
if (data === void 0) return "";
|
|
8293
|
+
if (data instanceof Error) {
|
|
8294
|
+
const info = extractErrorInfo(data);
|
|
8295
|
+
const stack = extractErrorStack(data);
|
|
8296
|
+
return JSON.stringify(info) + (stack ? `
|
|
8297
|
+
${stack}` : "");
|
|
8298
|
+
}
|
|
8299
|
+
if (typeof data === "string") return data;
|
|
8300
|
+
try {
|
|
8301
|
+
return JSON.stringify(data);
|
|
8302
|
+
} catch {
|
|
8303
|
+
return "[unserializable data]";
|
|
8304
|
+
}
|
|
8305
|
+
}
|
|
8306
|
+
function ensureDir2(dir) {
|
|
8307
|
+
if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
|
|
8308
|
+
}
|
|
8309
|
+
var instance = null;
|
|
8310
|
+
function initAppLogger(logsDir) {
|
|
8311
|
+
instance = new AppLogger(logsDir);
|
|
8312
|
+
}
|
|
8313
|
+
var appLogger = {
|
|
8314
|
+
debug: (scope, message, data) => instance?.debug(scope, message, data),
|
|
8315
|
+
info: (scope, message, data) => instance?.info(scope, message, data),
|
|
8316
|
+
warn: (scope, message, data) => instance?.warn(scope, message, data),
|
|
8317
|
+
error: (scope, message, data) => instance?.error(scope, message, data),
|
|
8318
|
+
getLogPath: () => instance?.getLogPath() ?? null
|
|
8319
|
+
};
|
|
8320
|
+
|
|
8321
|
+
// ../../packages/node-runtime/src/node-path-provider.ts
|
|
8322
|
+
import * as fs25 from "fs";
|
|
8323
|
+
import * as os2 from "os";
|
|
8324
|
+
import * as path20 from "path";
|
|
6201
8325
|
|
|
6202
8326
|
// ../../packages/node-runtime/src/data-dir-switch.ts
|
|
6203
|
-
import * as
|
|
6204
|
-
import * as
|
|
8327
|
+
import * as fs24 from "fs";
|
|
8328
|
+
import * as path19 from "path";
|
|
6205
8329
|
var CHATLAB_MARKER_FILE = ".chatlab";
|
|
6206
8330
|
var USER_DATA_REQUIRED_DIRS = ["databases"];
|
|
6207
8331
|
var PENDING_MIGRATION_FILE = "data-dir-migration.json";
|
|
@@ -6222,15 +8346,15 @@ var DANGEROUS_PATHS = [
|
|
|
6222
8346
|
"/Library"
|
|
6223
8347
|
];
|
|
6224
8348
|
function normalizePathForCompare(input) {
|
|
6225
|
-
const resolved =
|
|
6226
|
-
const normalized =
|
|
8349
|
+
const resolved = path19.resolve(input);
|
|
8350
|
+
const normalized = path19.normalize(resolved);
|
|
6227
8351
|
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
6228
8352
|
}
|
|
6229
8353
|
function isSubPath(parent, child) {
|
|
6230
8354
|
const parentPath = normalizePathForCompare(parent);
|
|
6231
8355
|
const childPath = normalizePathForCompare(child);
|
|
6232
8356
|
if (parentPath === childPath) return false;
|
|
6233
|
-
return childPath.startsWith(`${parentPath}${
|
|
8357
|
+
return childPath.startsWith(`${parentPath}${path19.sep}`);
|
|
6234
8358
|
}
|
|
6235
8359
|
function isPathSafe(targetPath) {
|
|
6236
8360
|
const normalizedTarget = targetPath.toLowerCase().replace(/\//g, "\\");
|
|
@@ -6242,37 +8366,37 @@ function isPathSafe(targetPath) {
|
|
|
6242
8366
|
}
|
|
6243
8367
|
return true;
|
|
6244
8368
|
}
|
|
6245
|
-
function
|
|
6246
|
-
if (!
|
|
6247
|
-
|
|
8369
|
+
function ensureDir3(dirPath) {
|
|
8370
|
+
if (!fs24.existsSync(dirPath)) {
|
|
8371
|
+
fs24.mkdirSync(dirPath, { recursive: true });
|
|
6248
8372
|
}
|
|
6249
8373
|
}
|
|
6250
8374
|
function hasChatLabUserDataStructure(entries) {
|
|
6251
8375
|
return entries.includes(CHATLAB_MARKER_FILE) && USER_DATA_REQUIRED_DIRS.every((dir) => entries.includes(dir));
|
|
6252
8376
|
}
|
|
6253
8377
|
function hasChatLabDatabaseFiles(dirPath, entries) {
|
|
6254
|
-
const dirEntries = entries ??
|
|
8378
|
+
const dirEntries = entries ?? fs24.readdirSync(dirPath);
|
|
6255
8379
|
if (!dirEntries.includes("databases")) return false;
|
|
6256
|
-
const dbDir =
|
|
8380
|
+
const dbDir = path19.join(dirPath, "databases");
|
|
6257
8381
|
try {
|
|
6258
|
-
return
|
|
8382
|
+
return fs24.existsSync(dbDir) && fs24.readdirSync(dbDir).some((file) => file.endsWith(".db"));
|
|
6259
8383
|
} catch {
|
|
6260
8384
|
return false;
|
|
6261
8385
|
}
|
|
6262
8386
|
}
|
|
6263
8387
|
function isExistingUserDataDir(dirPath) {
|
|
6264
|
-
if (!
|
|
8388
|
+
if (!fs24.existsSync(dirPath)) return false;
|
|
6265
8389
|
try {
|
|
6266
|
-
const entries =
|
|
8390
|
+
const entries = fs24.readdirSync(dirPath);
|
|
6267
8391
|
return hasChatLabUserDataStructure(entries) || hasChatLabDatabaseFiles(dirPath, entries);
|
|
6268
8392
|
} catch {
|
|
6269
8393
|
return false;
|
|
6270
8394
|
}
|
|
6271
8395
|
}
|
|
6272
8396
|
function isUserDataDirSafeToUse(dirPath) {
|
|
6273
|
-
if (!
|
|
8397
|
+
if (!fs24.existsSync(dirPath)) return true;
|
|
6274
8398
|
try {
|
|
6275
|
-
const entries =
|
|
8399
|
+
const entries = fs24.readdirSync(dirPath);
|
|
6276
8400
|
if (entries.length === 0) return true;
|
|
6277
8401
|
return hasChatLabUserDataStructure(entries) || hasChatLabDatabaseFiles(dirPath, entries);
|
|
6278
8402
|
} catch {
|
|
@@ -6280,26 +8404,26 @@ function isUserDataDirSafeToUse(dirPath) {
|
|
|
6280
8404
|
}
|
|
6281
8405
|
}
|
|
6282
8406
|
function isDirectoryEmptyOrMissing(dirPath) {
|
|
6283
|
-
if (!
|
|
8407
|
+
if (!fs24.existsSync(dirPath)) return true;
|
|
6284
8408
|
try {
|
|
6285
|
-
return
|
|
8409
|
+
return fs24.readdirSync(dirPath).length === 0;
|
|
6286
8410
|
} catch {
|
|
6287
8411
|
return false;
|
|
6288
8412
|
}
|
|
6289
8413
|
}
|
|
6290
|
-
function copyDirMerge(src, dest, mkdir =
|
|
6291
|
-
if (!
|
|
8414
|
+
function copyDirMerge(src, dest, mkdir = ensureDir3, stats = { copied: 0, skipped: 0, errors: [] }) {
|
|
8415
|
+
if (!fs24.existsSync(src)) return stats;
|
|
6292
8416
|
try {
|
|
6293
8417
|
mkdir(dest);
|
|
6294
|
-
const entries =
|
|
8418
|
+
const entries = fs24.readdirSync(src, { withFileTypes: true });
|
|
6295
8419
|
for (const entry of entries) {
|
|
6296
|
-
const srcPath =
|
|
6297
|
-
const destPath =
|
|
8420
|
+
const srcPath = path19.join(src, entry.name);
|
|
8421
|
+
const destPath = path19.join(dest, entry.name);
|
|
6298
8422
|
try {
|
|
6299
8423
|
if (entry.isDirectory()) {
|
|
6300
8424
|
copyDirMerge(srcPath, destPath, mkdir, stats);
|
|
6301
|
-
} else if (!
|
|
6302
|
-
|
|
8425
|
+
} else if (!fs24.existsSync(destPath)) {
|
|
8426
|
+
fs24.copyFileSync(srcPath, destPath);
|
|
6303
8427
|
stats.copied++;
|
|
6304
8428
|
} else {
|
|
6305
8429
|
stats.skipped++;
|
|
@@ -6324,10 +8448,10 @@ function createPendingDataDirMigration(input) {
|
|
|
6324
8448
|
}
|
|
6325
8449
|
function runPendingDataDirMigration(pending, deps) {
|
|
6326
8450
|
const copy = deps.copyDirMerge ?? copyDirMerge;
|
|
6327
|
-
const mkdir = deps.ensureDir ??
|
|
8451
|
+
const mkdir = deps.ensureDir ?? ensureDir3;
|
|
6328
8452
|
let stats = { copied: 0, skipped: 0, errors: [] };
|
|
6329
|
-
if (pending.migrate &&
|
|
6330
|
-
if (!
|
|
8453
|
+
if (pending.migrate && path19.resolve(pending.from) !== path19.resolve(pending.to)) {
|
|
8454
|
+
if (!fs24.existsSync(pending.from)) {
|
|
6331
8455
|
return {
|
|
6332
8456
|
success: false,
|
|
6333
8457
|
from: pending.from,
|
|
@@ -6356,7 +8480,7 @@ function runPendingDataDirMigration(pending, deps) {
|
|
|
6356
8480
|
}
|
|
6357
8481
|
deps.writeUserDataDir(pending.to);
|
|
6358
8482
|
deps.clearPendingMigration();
|
|
6359
|
-
if (pending.deleteSourceOnSuccess &&
|
|
8483
|
+
if (pending.deleteSourceOnSuccess && path19.resolve(pending.from) !== path19.resolve(pending.to)) {
|
|
6360
8484
|
deps.markPendingDeleteDir?.(pending.from);
|
|
6361
8485
|
}
|
|
6362
8486
|
return {
|
|
@@ -6369,13 +8493,13 @@ function runPendingDataDirMigration(pending, deps) {
|
|
|
6369
8493
|
};
|
|
6370
8494
|
}
|
|
6371
8495
|
function getPendingMigrationPath(systemDir) {
|
|
6372
|
-
return
|
|
8496
|
+
return path19.join(systemDir, "settings", PENDING_MIGRATION_FILE);
|
|
6373
8497
|
}
|
|
6374
8498
|
function getPendingNodeDataDirMigration(systemDir) {
|
|
6375
8499
|
const filePath = getPendingMigrationPath(systemDir);
|
|
6376
|
-
if (!
|
|
8500
|
+
if (!fs24.existsSync(filePath)) return null;
|
|
6377
8501
|
try {
|
|
6378
|
-
const parsed = JSON.parse(
|
|
8502
|
+
const parsed = JSON.parse(fs24.readFileSync(filePath, "utf-8"));
|
|
6379
8503
|
if (!parsed.from || !parsed.to || typeof parsed.migrate !== "boolean") return null;
|
|
6380
8504
|
return parsed;
|
|
6381
8505
|
} catch {
|
|
@@ -6384,23 +8508,23 @@ function getPendingNodeDataDirMigration(systemDir) {
|
|
|
6384
8508
|
}
|
|
6385
8509
|
function clearPendingNodeDataDirMigration(systemDir) {
|
|
6386
8510
|
const filePath = getPendingMigrationPath(systemDir);
|
|
6387
|
-
if (
|
|
6388
|
-
|
|
8511
|
+
if (fs24.existsSync(filePath)) {
|
|
8512
|
+
fs24.unlinkSync(filePath);
|
|
6389
8513
|
}
|
|
6390
8514
|
}
|
|
6391
8515
|
function deleteOldUserDataDirIfSafe(dirPath, currentDir, removeDir) {
|
|
6392
|
-
if (
|
|
8516
|
+
if (path19.resolve(dirPath) === path19.resolve(currentDir)) return false;
|
|
6393
8517
|
if (!isPathSafe(dirPath)) return false;
|
|
6394
|
-
if (!
|
|
8518
|
+
if (!fs24.existsSync(dirPath)) return false;
|
|
6395
8519
|
if (!isExistingUserDataDir(dirPath)) return false;
|
|
6396
|
-
const remove = removeDir ?? ((dir) =>
|
|
8520
|
+
const remove = removeDir ?? ((dir) => fs24.rmSync(dir, { recursive: true, force: true }));
|
|
6397
8521
|
remove(dirPath);
|
|
6398
8522
|
return true;
|
|
6399
8523
|
}
|
|
6400
8524
|
function writePendingNodeDataDirMigration(systemDir, pending) {
|
|
6401
8525
|
const filePath = getPendingMigrationPath(systemDir);
|
|
6402
|
-
|
|
6403
|
-
|
|
8526
|
+
ensureDir3(path19.dirname(filePath));
|
|
8527
|
+
fs24.writeFileSync(filePath, JSON.stringify(pending, null, 2), "utf-8");
|
|
6404
8528
|
}
|
|
6405
8529
|
function createNodeDataDirSwitch(input) {
|
|
6406
8530
|
if (input.envDataDir) {
|
|
@@ -6408,16 +8532,16 @@ function createNodeDataDirSwitch(input) {
|
|
|
6408
8532
|
}
|
|
6409
8533
|
const newDir = (input.targetDir?.trim() || input.defaultDir || "").trim();
|
|
6410
8534
|
if (!newDir) return { success: false, error: "Data directory is required" };
|
|
6411
|
-
if (!
|
|
8535
|
+
if (!path19.isAbsolute(newDir)) return { success: false, error: "Data directory must be an absolute path" };
|
|
6412
8536
|
if (!isPathSafe(newDir)) return { success: false, error: "System directories cannot be used as data directory" };
|
|
6413
8537
|
const migrate = input.migrate !== false;
|
|
6414
|
-
if (migrate &&
|
|
8538
|
+
if (migrate && path19.resolve(input.currentDir) !== path19.resolve(newDir) && isSubPath(input.currentDir, newDir)) {
|
|
6415
8539
|
return { success: false, error: "Target directory cannot be inside current data directory" };
|
|
6416
8540
|
}
|
|
6417
8541
|
if (!isUserDataDirSafeToUse(newDir)) {
|
|
6418
8542
|
return { success: false, error: "Target directory is not empty and is not a ChatLab data directory" };
|
|
6419
8543
|
}
|
|
6420
|
-
if (
|
|
8544
|
+
if (path19.resolve(input.currentDir) === path19.resolve(newDir)) {
|
|
6421
8545
|
clearPendingNodeDataDirMigration(input.systemDir);
|
|
6422
8546
|
return { success: true, from: input.currentDir, to: newDir, requiresRelaunch: false };
|
|
6423
8547
|
}
|
|
@@ -6453,7 +8577,7 @@ function applyPendingNodeDataDirMigration(systemDir, deps = {}) {
|
|
|
6453
8577
|
}
|
|
6454
8578
|
|
|
6455
8579
|
// ../../packages/node-runtime/src/node-path-provider.ts
|
|
6456
|
-
var SYSTEM_DIR =
|
|
8580
|
+
var SYSTEM_DIR = path20.join(os2.homedir(), ".chatlab");
|
|
6457
8581
|
var _pendingElectronDataWarning = false;
|
|
6458
8582
|
function hasPendingElectronDataWarning() {
|
|
6459
8583
|
return _pendingElectronDataWarning;
|
|
@@ -6476,28 +8600,28 @@ var NodePathProvider = class {
|
|
|
6476
8600
|
return this.userDataDir;
|
|
6477
8601
|
}
|
|
6478
8602
|
getDatabaseDir() {
|
|
6479
|
-
return
|
|
8603
|
+
return path20.join(this.userDataDir, "databases");
|
|
6480
8604
|
}
|
|
6481
8605
|
getVectorDir() {
|
|
6482
|
-
return
|
|
8606
|
+
return path20.join(this.userDataDir, "vector");
|
|
6483
8607
|
}
|
|
6484
8608
|
getAiDataDir() {
|
|
6485
|
-
return
|
|
8609
|
+
return path20.join(this.systemDir, "ai");
|
|
6486
8610
|
}
|
|
6487
8611
|
getSettingsDir() {
|
|
6488
|
-
return
|
|
8612
|
+
return path20.join(this.systemDir, "settings");
|
|
6489
8613
|
}
|
|
6490
8614
|
getCacheDir() {
|
|
6491
|
-
return
|
|
8615
|
+
return path20.join(this.systemDir, "cache");
|
|
6492
8616
|
}
|
|
6493
8617
|
getTempDir() {
|
|
6494
|
-
return
|
|
8618
|
+
return path20.join(this.systemDir, "temp");
|
|
6495
8619
|
}
|
|
6496
8620
|
getLogsDir() {
|
|
6497
|
-
return
|
|
8621
|
+
return path20.join(this.systemDir, "logs");
|
|
6498
8622
|
}
|
|
6499
8623
|
getDownloadsDir() {
|
|
6500
|
-
return
|
|
8624
|
+
return path20.join(os2.homedir(), "Downloads");
|
|
6501
8625
|
}
|
|
6502
8626
|
/**
|
|
6503
8627
|
* 确保系统目录和用户数据目录都存在
|
|
@@ -6515,13 +8639,13 @@ var NodePathProvider = class {
|
|
|
6515
8639
|
this.getLogsDir()
|
|
6516
8640
|
];
|
|
6517
8641
|
for (const dir of dirs) {
|
|
6518
|
-
if (!
|
|
6519
|
-
|
|
8642
|
+
if (!fs25.existsSync(dir)) {
|
|
8643
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
6520
8644
|
}
|
|
6521
8645
|
}
|
|
6522
|
-
const markerPath =
|
|
6523
|
-
if (!
|
|
6524
|
-
|
|
8646
|
+
const markerPath = path20.join(this.userDataDir, ".chatlab");
|
|
8647
|
+
if (!fs25.existsSync(markerPath)) {
|
|
8648
|
+
fs25.writeFileSync(markerPath, "ChatLab Data Directory", "utf-8");
|
|
6525
8649
|
}
|
|
6526
8650
|
}
|
|
6527
8651
|
};
|
|
@@ -6547,11 +8671,14 @@ function resolveUserDataDir() {
|
|
|
6547
8671
|
return defaultDir;
|
|
6548
8672
|
}
|
|
6549
8673
|
function getDefaultNodeUserDataDir() {
|
|
6550
|
-
return
|
|
8674
|
+
return path20.join(os2.homedir(), ".chatlab", "data");
|
|
8675
|
+
}
|
|
8676
|
+
function getSystemLogsDir() {
|
|
8677
|
+
return path20.join(SYSTEM_DIR, "logs");
|
|
6551
8678
|
}
|
|
6552
8679
|
function expandHome(filePath) {
|
|
6553
8680
|
if (filePath.startsWith("~/") || filePath === "~") {
|
|
6554
|
-
return
|
|
8681
|
+
return path20.join(os2.homedir(), filePath.slice(1));
|
|
6555
8682
|
}
|
|
6556
8683
|
return filePath;
|
|
6557
8684
|
}
|
|
@@ -6568,12 +8695,12 @@ function createJiebaNlpProvider(dictType = "default") {
|
|
|
6568
8695
|
}
|
|
6569
8696
|
|
|
6570
8697
|
// ../../packages/node-runtime/src/cache/analytics-cache.ts
|
|
6571
|
-
import * as
|
|
8698
|
+
import * as fs26 from "fs";
|
|
6572
8699
|
function getDbFileVersion(dbPath) {
|
|
6573
8700
|
const parts = [];
|
|
6574
8701
|
for (const p of [dbPath, `${dbPath}-wal`]) {
|
|
6575
8702
|
try {
|
|
6576
|
-
const st =
|
|
8703
|
+
const st = fs26.statSync(p);
|
|
6577
8704
|
parts.push(`${Math.floor(st.mtimeMs)}:${st.size}`);
|
|
6578
8705
|
} catch {
|
|
6579
8706
|
parts.push("-");
|
|
@@ -6592,8 +8719,8 @@ function getOrComputeAnalysisCache(sessionId, key, queryCacheDir, version, compu
|
|
|
6592
8719
|
}
|
|
6593
8720
|
|
|
6594
8721
|
// ../../packages/node-runtime/src/preferences.ts
|
|
6595
|
-
import * as
|
|
6596
|
-
import * as
|
|
8722
|
+
import * as fs27 from "fs";
|
|
8723
|
+
import * as path21 from "path";
|
|
6597
8724
|
var DEFAULTS = {
|
|
6598
8725
|
pinnedSessionIds: [],
|
|
6599
8726
|
aiPreprocessConfig: {
|
|
@@ -6639,13 +8766,13 @@ var PreferencesManager = class {
|
|
|
6639
8766
|
filePath;
|
|
6640
8767
|
cache = null;
|
|
6641
8768
|
constructor(systemDir) {
|
|
6642
|
-
this.filePath =
|
|
8769
|
+
this.filePath = path21.join(systemDir, "preferences.json");
|
|
6643
8770
|
}
|
|
6644
8771
|
load() {
|
|
6645
8772
|
if (this.cache) return this.cache;
|
|
6646
8773
|
try {
|
|
6647
|
-
if (
|
|
6648
|
-
const raw =
|
|
8774
|
+
if (fs27.existsSync(this.filePath)) {
|
|
8775
|
+
const raw = fs27.readFileSync(this.filePath, "utf-8");
|
|
6649
8776
|
const parsed = JSON.parse(raw);
|
|
6650
8777
|
const migrated = this.migrateLegacyDesensitizeRules(parsed, raw);
|
|
6651
8778
|
this.cache = this.mergeDefaults(migrated.preferences);
|
|
@@ -6760,21 +8887,21 @@ var PreferencesManager = class {
|
|
|
6760
8887
|
};
|
|
6761
8888
|
}
|
|
6762
8889
|
backupLegacyPreferences(rawContent) {
|
|
6763
|
-
const backupDir =
|
|
6764
|
-
if (!
|
|
6765
|
-
|
|
8890
|
+
const backupDir = path21.join(path21.dirname(this.filePath), "backups");
|
|
8891
|
+
if (!fs27.existsSync(backupDir)) {
|
|
8892
|
+
fs27.mkdirSync(backupDir, { recursive: true });
|
|
6766
8893
|
}
|
|
6767
8894
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
6768
|
-
const backupPath =
|
|
6769
|
-
|
|
8895
|
+
const backupPath = path21.join(backupDir, `preferences-pre-desensitize-groups-${timestamp}.json`);
|
|
8896
|
+
fs27.writeFileSync(backupPath, rawContent, "utf-8");
|
|
6770
8897
|
console.info(`[Preferences] Backed up legacy desensitize rules to ${backupPath}`);
|
|
6771
8898
|
}
|
|
6772
8899
|
writePreferences(preferences) {
|
|
6773
|
-
const dir =
|
|
6774
|
-
if (!
|
|
6775
|
-
|
|
8900
|
+
const dir = path21.dirname(this.filePath);
|
|
8901
|
+
if (!fs27.existsSync(dir)) {
|
|
8902
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
6776
8903
|
}
|
|
6777
|
-
|
|
8904
|
+
fs27.writeFileSync(this.filePath, JSON.stringify(preferences, null, 2), "utf-8");
|
|
6778
8905
|
}
|
|
6779
8906
|
/**
|
|
6780
8907
|
* Deep merge: arrays are replaced (not concatenated), objects are merged.
|
|
@@ -6894,8 +9021,8 @@ function* serializeChatLabToJsonl(data) {
|
|
|
6894
9021
|
}
|
|
6895
9022
|
|
|
6896
9023
|
// ../../packages/node-runtime/src/services/analytics.ts
|
|
6897
|
-
import * as
|
|
6898
|
-
import * as
|
|
9024
|
+
import * as fs28 from "fs";
|
|
9025
|
+
import * as path22 from "path";
|
|
6899
9026
|
var REGIONS = {
|
|
6900
9027
|
US: "https://us.aptabase.com",
|
|
6901
9028
|
EU: "https://eu.aptabase.com"
|
|
@@ -6908,7 +9035,7 @@ var AnalyticsService = class {
|
|
|
6908
9035
|
appVersion;
|
|
6909
9036
|
sessionId;
|
|
6910
9037
|
constructor(systemDir, appKey, appVersion) {
|
|
6911
|
-
this.dataPath =
|
|
9038
|
+
this.dataPath = path22.join(systemDir, "analytics.json");
|
|
6912
9039
|
this.appKey = appKey;
|
|
6913
9040
|
this.appVersion = appVersion;
|
|
6914
9041
|
this.sessionId = `${Math.floor(Date.now() / 1e3)}${Math.floor(Math.random() * 1e8).toString().padStart(8, "0")}`;
|
|
@@ -6918,8 +9045,8 @@ var AnalyticsService = class {
|
|
|
6918
9045
|
}
|
|
6919
9046
|
load() {
|
|
6920
9047
|
try {
|
|
6921
|
-
if (
|
|
6922
|
-
return { ...DEFAULT_DATA, ...JSON.parse(
|
|
9048
|
+
if (fs28.existsSync(this.dataPath)) {
|
|
9049
|
+
return { ...DEFAULT_DATA, ...JSON.parse(fs28.readFileSync(this.dataPath, "utf-8")) };
|
|
6923
9050
|
}
|
|
6924
9051
|
} catch (_e) {
|
|
6925
9052
|
}
|
|
@@ -6927,7 +9054,7 @@ var AnalyticsService = class {
|
|
|
6927
9054
|
}
|
|
6928
9055
|
save(data) {
|
|
6929
9056
|
try {
|
|
6930
|
-
|
|
9057
|
+
fs28.writeFileSync(this.dataPath, JSON.stringify(data, null, 2), "utf-8");
|
|
6931
9058
|
} catch (e) {
|
|
6932
9059
|
console.error("[Analytics] Failed to save:", e);
|
|
6933
9060
|
}
|
|
@@ -7047,7 +9174,7 @@ __export(semantic_index_exports, {
|
|
|
7047
9174
|
});
|
|
7048
9175
|
|
|
7049
9176
|
// ../../packages/node-runtime/src/semantic-index/worker-client.ts
|
|
7050
|
-
import
|
|
9177
|
+
import path23 from "path";
|
|
7051
9178
|
|
|
7052
9179
|
// ../../packages/node-runtime/src/semantic-index/worker-thread-transport.ts
|
|
7053
9180
|
import { Worker } from "worker_threads";
|
|
@@ -7069,22 +9196,22 @@ function createDefaultWorker(startup, entryUrlInput) {
|
|
|
7069
9196
|
register();
|
|
7070
9197
|
await import(${JSON.stringify(entryUrl.href)});
|
|
7071
9198
|
`;
|
|
7072
|
-
const
|
|
9199
|
+
const options2 = {
|
|
7073
9200
|
eval: true,
|
|
7074
9201
|
type: "module",
|
|
7075
9202
|
workerData: startup,
|
|
7076
9203
|
execArgv: []
|
|
7077
9204
|
};
|
|
7078
|
-
return new Worker(bootstrap,
|
|
9205
|
+
return new Worker(bootstrap, options2);
|
|
7079
9206
|
}
|
|
7080
9207
|
var SemanticIndexWorkerThreadTransport = class {
|
|
7081
9208
|
worker;
|
|
7082
9209
|
pending = /* @__PURE__ */ new Map();
|
|
7083
9210
|
requestId = 0;
|
|
7084
9211
|
closeTimeoutMs;
|
|
7085
|
-
constructor(
|
|
7086
|
-
this.closeTimeoutMs =
|
|
7087
|
-
this.worker =
|
|
9212
|
+
constructor(options2) {
|
|
9213
|
+
this.closeTimeoutMs = options2.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
|
|
9214
|
+
this.worker = options2.workerFactory?.() ?? createDefaultWorker(options2.startup, options2.workerEntryUrl);
|
|
7088
9215
|
this.worker.on("message", (message) => this.handleMessage(message));
|
|
7089
9216
|
this.worker.on("error", (error) => this.rejectAll(error));
|
|
7090
9217
|
this.worker.on("exit", (code) => {
|
|
@@ -7093,8 +9220,8 @@ var SemanticIndexWorkerThreadTransport = class {
|
|
|
7093
9220
|
}
|
|
7094
9221
|
request(method, args) {
|
|
7095
9222
|
const id = `si_${++this.requestId}`;
|
|
7096
|
-
return new Promise((
|
|
7097
|
-
this.pending.set(id, { resolve:
|
|
9223
|
+
return new Promise((resolve3, reject) => {
|
|
9224
|
+
this.pending.set(id, { resolve: resolve3, reject });
|
|
7098
9225
|
this.worker.postMessage({ id, method, args });
|
|
7099
9226
|
});
|
|
7100
9227
|
}
|
|
@@ -7105,8 +9232,8 @@ var SemanticIndexWorkerThreadTransport = class {
|
|
|
7105
9232
|
}
|
|
7106
9233
|
async requestRuntimeClose() {
|
|
7107
9234
|
let timeout = null;
|
|
7108
|
-
const timeoutPromise = new Promise((
|
|
7109
|
-
timeout = setTimeout(
|
|
9235
|
+
const timeoutPromise = new Promise((resolve3) => {
|
|
9236
|
+
timeout = setTimeout(resolve3, this.closeTimeoutMs);
|
|
7110
9237
|
});
|
|
7111
9238
|
try {
|
|
7112
9239
|
await Promise.race([this.request("__close", []).then(() => void 0), timeoutPromise]);
|
|
@@ -7131,8 +9258,8 @@ var SemanticIndexWorkerThreadTransport = class {
|
|
|
7131
9258
|
}
|
|
7132
9259
|
}
|
|
7133
9260
|
};
|
|
7134
|
-
function createSemanticIndexWorkerThreadTransport(
|
|
7135
|
-
return new SemanticIndexWorkerThreadTransport(
|
|
9261
|
+
function createSemanticIndexWorkerThreadTransport(options2) {
|
|
9262
|
+
return new SemanticIndexWorkerThreadTransport(options2);
|
|
7136
9263
|
}
|
|
7137
9264
|
|
|
7138
9265
|
// ../../packages/node-runtime/src/semantic-index/worker-client.ts
|
|
@@ -7153,24 +9280,25 @@ var SemanticIndexWorkerClient = class {
|
|
|
7153
9280
|
timers;
|
|
7154
9281
|
resolveApiKey;
|
|
7155
9282
|
writeAuthProfile;
|
|
7156
|
-
constructor(
|
|
7157
|
-
this.configStore =
|
|
7158
|
-
this.transportFactory =
|
|
7159
|
-
this.idleTimeoutMs =
|
|
7160
|
-
this.timers =
|
|
7161
|
-
this.resolveApiKey =
|
|
7162
|
-
this.writeAuthProfile =
|
|
9283
|
+
constructor(options2) {
|
|
9284
|
+
this.configStore = options2.configStore;
|
|
9285
|
+
this.transportFactory = options2.transportFactory;
|
|
9286
|
+
this.idleTimeoutMs = options2.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
|
|
9287
|
+
this.timers = options2.timers ?? defaultTimers;
|
|
9288
|
+
this.resolveApiKey = options2.resolveApiKey ?? resolveApiKey;
|
|
9289
|
+
this.writeAuthProfile = options2.writeAuthProfile;
|
|
7163
9290
|
}
|
|
7164
9291
|
getConfig() {
|
|
7165
9292
|
return this.configStore.get();
|
|
7166
9293
|
}
|
|
7167
|
-
async setConfig(config,
|
|
9294
|
+
async setConfig(config, options2) {
|
|
7168
9295
|
const saved = persistSemanticIndexConfig(this.configStore, config, {
|
|
7169
|
-
apiKey:
|
|
9296
|
+
apiKey: options2?.apiKey,
|
|
7170
9297
|
writeAuthProfile: this.writeAuthProfile
|
|
7171
9298
|
});
|
|
7172
9299
|
if (!saved.enabled) this.clearActiveBuildTracking();
|
|
7173
|
-
|
|
9300
|
+
const needsWorker = saved.enabled && saved.mode === "local" && this.configStore.isConfigured();
|
|
9301
|
+
if (!this.transport && !needsWorker) return saved;
|
|
7174
9302
|
return await this.call("setConfig", [saved]);
|
|
7175
9303
|
}
|
|
7176
9304
|
isConfigured() {
|
|
@@ -7179,11 +9307,15 @@ var SemanticIndexWorkerClient = class {
|
|
|
7179
9307
|
hasApiKey() {
|
|
7180
9308
|
return resolveSemanticIndexApiKeySet(this.configStore.get(), this.resolveApiKey);
|
|
7181
9309
|
}
|
|
9310
|
+
async getModelStatus() {
|
|
9311
|
+
if (!this.transport) return "idle";
|
|
9312
|
+
return this.call("getModelStatus", []);
|
|
9313
|
+
}
|
|
7182
9314
|
enable(sessionId) {
|
|
7183
9315
|
return this.call("enable", [sessionId]);
|
|
7184
9316
|
}
|
|
7185
|
-
|
|
7186
|
-
return this.call("
|
|
9317
|
+
remove(sessionId) {
|
|
9318
|
+
return this.call("remove", [sessionId]);
|
|
7187
9319
|
}
|
|
7188
9320
|
async build(sessionId) {
|
|
7189
9321
|
this.activeBuildSessionIds.add(sessionId);
|
|
@@ -7246,11 +9378,11 @@ var SemanticIndexWorkerClient = class {
|
|
|
7246
9378
|
if (!this.canRunFromLocalConfig()) return false;
|
|
7247
9379
|
return await this.callProbe("canSearch", [sessionId], false);
|
|
7248
9380
|
}
|
|
7249
|
-
search(sessionId, query,
|
|
7250
|
-
return this.call("search", [sessionId, query,
|
|
9381
|
+
search(sessionId, query, options2) {
|
|
9382
|
+
return this.call("search", [sessionId, query, options2]);
|
|
7251
9383
|
}
|
|
7252
|
-
searchForTool(sessionId, query,
|
|
7253
|
-
return this.call("searchForTool", [sessionId, query,
|
|
9384
|
+
searchForTool(sessionId, query, options2) {
|
|
9385
|
+
return this.call("searchForTool", [sessionId, query, options2]);
|
|
7254
9386
|
}
|
|
7255
9387
|
cleanupUnused() {
|
|
7256
9388
|
return this.call("cleanupUnused", []);
|
|
@@ -7262,7 +9394,7 @@ var SemanticIndexWorkerClient = class {
|
|
|
7262
9394
|
this.clearIdleTimer();
|
|
7263
9395
|
await this.closeTransport();
|
|
7264
9396
|
}
|
|
7265
|
-
async call(method, args,
|
|
9397
|
+
async call(method, args, options2) {
|
|
7266
9398
|
const transport = this.ensureTransport();
|
|
7267
9399
|
this.pendingRequests++;
|
|
7268
9400
|
this.clearIdleTimer();
|
|
@@ -7270,12 +9402,12 @@ var SemanticIndexWorkerClient = class {
|
|
|
7270
9402
|
return await transport.request(method, args);
|
|
7271
9403
|
} finally {
|
|
7272
9404
|
this.pendingRequests--;
|
|
7273
|
-
if (
|
|
9405
|
+
if (options2?.scheduleIdle !== false) this.scheduleIdleCloseIfNeeded();
|
|
7274
9406
|
}
|
|
7275
9407
|
}
|
|
7276
|
-
async callProbe(method, args, fallback,
|
|
9408
|
+
async callProbe(method, args, fallback, options2) {
|
|
7277
9409
|
try {
|
|
7278
|
-
return await this.call(method, args,
|
|
9410
|
+
return await this.call(method, args, options2);
|
|
7279
9411
|
} catch {
|
|
7280
9412
|
await this.closeFailedProbeTransport();
|
|
7281
9413
|
return fallback;
|
|
@@ -7345,25 +9477,25 @@ var SemanticIndexWorkerClient = class {
|
|
|
7345
9477
|
}
|
|
7346
9478
|
}
|
|
7347
9479
|
};
|
|
7348
|
-
function createSemanticIndexWorkerClient(
|
|
7349
|
-
return new SemanticIndexWorkerClient(
|
|
9480
|
+
function createSemanticIndexWorkerClient(options2) {
|
|
9481
|
+
return new SemanticIndexWorkerClient(options2);
|
|
7350
9482
|
}
|
|
7351
|
-
function createSemanticIndexWorkerRuntimeClient(
|
|
9483
|
+
function createSemanticIndexWorkerRuntimeClient(options2) {
|
|
7352
9484
|
const configStore = new SemanticIndexConfigStore(
|
|
7353
|
-
|
|
9485
|
+
path23.join(options2.pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE)
|
|
7354
9486
|
);
|
|
7355
9487
|
return createSemanticIndexWorkerClient({
|
|
7356
9488
|
configStore,
|
|
7357
|
-
idleTimeoutMs:
|
|
7358
|
-
resolveApiKey:
|
|
7359
|
-
writeAuthProfile:
|
|
9489
|
+
idleTimeoutMs: options2.idleTimeoutMs,
|
|
9490
|
+
resolveApiKey: options2.resolveApiKey,
|
|
9491
|
+
writeAuthProfile: options2.writeAuthProfile,
|
|
7360
9492
|
transportFactory: () => createSemanticIndexWorkerThreadTransport({
|
|
7361
|
-
workerEntryUrl:
|
|
9493
|
+
workerEntryUrl: options2.workerEntryUrl,
|
|
7362
9494
|
startup: {
|
|
7363
|
-
paths: snapshotPathProvider(
|
|
7364
|
-
runtime:
|
|
7365
|
-
nativeBinding:
|
|
7366
|
-
sqliteVecLoadablePath:
|
|
9495
|
+
paths: snapshotPathProvider(options2.pathProvider),
|
|
9496
|
+
runtime: options2.runtime,
|
|
9497
|
+
nativeBinding: options2.nativeBinding,
|
|
9498
|
+
sqliteVecLoadablePath: options2.sqliteVecLoadablePath
|
|
7367
9499
|
}
|
|
7368
9500
|
})
|
|
7369
9501
|
});
|
|
@@ -7405,6 +9537,13 @@ export {
|
|
|
7405
9537
|
streamParseFileInfo,
|
|
7406
9538
|
analyzeIncrementalImport,
|
|
7407
9539
|
incrementalImport,
|
|
9540
|
+
ArchiveImportError,
|
|
9541
|
+
validateArchiveEntryName,
|
|
9542
|
+
ZipArchiveReader,
|
|
9543
|
+
GoogleChatTakeoutResolver,
|
|
9544
|
+
ArchiveImportSourceManager,
|
|
9545
|
+
initAppLogger,
|
|
9546
|
+
appLogger,
|
|
7408
9547
|
isExistingUserDataDir,
|
|
7409
9548
|
isUserDataDirSafeToUse,
|
|
7410
9549
|
isDirectoryEmptyOrMissing,
|
|
@@ -7419,6 +9558,7 @@ export {
|
|
|
7419
9558
|
applyPendingNodeDataDirMigrationIfNeeded,
|
|
7420
9559
|
NodePathProvider,
|
|
7421
9560
|
getDefaultNodeUserDataDir,
|
|
9561
|
+
getSystemLogsDir,
|
|
7422
9562
|
createJiebaNlpProvider,
|
|
7423
9563
|
getDbFileVersion,
|
|
7424
9564
|
getOrComputeAnalysisCache,
|
|
@@ -7430,4 +9570,4 @@ export {
|
|
|
7430
9570
|
createSemanticIndexWorkerRuntimeClient,
|
|
7431
9571
|
semantic_index_exports
|
|
7432
9572
|
};
|
|
7433
|
-
//# sourceMappingURL=chunk-
|
|
9573
|
+
//# sourceMappingURL=chunk-GPF34WXV.mjs.map
|