openzca 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +164 -7
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -806,6 +806,159 @@ async function refreshCacheForProfile(profile, api) {
|
|
|
806
806
|
groups: groups.length
|
|
807
807
|
};
|
|
808
808
|
}
|
|
809
|
+
function parsePositiveIntFromEnv(name, fallback) {
|
|
810
|
+
const raw = process.env[name]?.trim();
|
|
811
|
+
if (!raw) return fallback;
|
|
812
|
+
const parsed = Number.parseInt(raw, 10);
|
|
813
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
814
|
+
return parsed;
|
|
815
|
+
}
|
|
816
|
+
function isListenerAlreadyStarted(error) {
|
|
817
|
+
if (!(error instanceof Error)) return false;
|
|
818
|
+
return /already started/i.test(error.message);
|
|
819
|
+
}
|
|
820
|
+
function toErrorText(error) {
|
|
821
|
+
return error instanceof Error ? error.message : String(error);
|
|
822
|
+
}
|
|
823
|
+
async function withTimeout(task, timeoutMs, message) {
|
|
824
|
+
let timeoutId;
|
|
825
|
+
try {
|
|
826
|
+
const timeout = new Promise((_, reject) => {
|
|
827
|
+
timeoutId = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
828
|
+
});
|
|
829
|
+
return await Promise.race([task, timeout]);
|
|
830
|
+
} finally {
|
|
831
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
async function stopUploadListenerSafely(api, command, waitClosedMs = 1500) {
|
|
835
|
+
await new Promise((resolve) => {
|
|
836
|
+
let settled = false;
|
|
837
|
+
let timeoutId;
|
|
838
|
+
const finish = () => {
|
|
839
|
+
if (settled) return;
|
|
840
|
+
settled = true;
|
|
841
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
842
|
+
api.listener.off("closed", onClosed);
|
|
843
|
+
resolve();
|
|
844
|
+
};
|
|
845
|
+
const onClosed = () => {
|
|
846
|
+
finish();
|
|
847
|
+
};
|
|
848
|
+
api.listener.on("closed", onClosed);
|
|
849
|
+
timeoutId = setTimeout(finish, waitClosedMs);
|
|
850
|
+
try {
|
|
851
|
+
api.listener.stop();
|
|
852
|
+
writeDebugLine("msg.upload.listener.stop", void 0, command);
|
|
853
|
+
} catch {
|
|
854
|
+
finish();
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
async function withUploadListener(api, command, task) {
|
|
859
|
+
const connectTimeoutMs = parsePositiveIntFromEnv(
|
|
860
|
+
"OPENZCA_UPLOAD_LISTENER_CONNECT_TIMEOUT_MS",
|
|
861
|
+
8e3
|
|
862
|
+
);
|
|
863
|
+
const uploadTimeoutMs = parsePositiveIntFromEnv(
|
|
864
|
+
"OPENZCA_UPLOAD_TIMEOUT_MS",
|
|
865
|
+
12e4
|
|
866
|
+
);
|
|
867
|
+
let startedHere = false;
|
|
868
|
+
const sinkError = (error) => {
|
|
869
|
+
writeDebugLine(
|
|
870
|
+
"msg.upload.listener.error",
|
|
871
|
+
{
|
|
872
|
+
message: toErrorText(error)
|
|
873
|
+
},
|
|
874
|
+
command
|
|
875
|
+
);
|
|
876
|
+
};
|
|
877
|
+
const sinkClosed = (code, reason) => {
|
|
878
|
+
writeDebugLine(
|
|
879
|
+
"msg.upload.listener.closed",
|
|
880
|
+
{
|
|
881
|
+
code,
|
|
882
|
+
reason: reason || void 0
|
|
883
|
+
},
|
|
884
|
+
command
|
|
885
|
+
);
|
|
886
|
+
};
|
|
887
|
+
api.listener.on("error", sinkError);
|
|
888
|
+
api.listener.on("closed", sinkClosed);
|
|
889
|
+
try {
|
|
890
|
+
await new Promise((resolve, reject) => {
|
|
891
|
+
let settled = false;
|
|
892
|
+
let timeoutId;
|
|
893
|
+
const cleanup = () => {
|
|
894
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
895
|
+
api.listener.off("connected", onConnected);
|
|
896
|
+
api.listener.off("error", onConnectError);
|
|
897
|
+
api.listener.off("closed", onConnectClosed);
|
|
898
|
+
};
|
|
899
|
+
const finish = (error) => {
|
|
900
|
+
if (settled) return;
|
|
901
|
+
settled = true;
|
|
902
|
+
cleanup();
|
|
903
|
+
if (error) {
|
|
904
|
+
reject(error);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
resolve();
|
|
908
|
+
};
|
|
909
|
+
const onConnected = () => {
|
|
910
|
+
writeDebugLine("msg.upload.listener.connected", void 0, command);
|
|
911
|
+
finish();
|
|
912
|
+
};
|
|
913
|
+
const onConnectError = (error) => {
|
|
914
|
+
finish(new Error(`Upload listener connection error: ${toErrorText(error)}`));
|
|
915
|
+
};
|
|
916
|
+
const onConnectClosed = (code, reason) => {
|
|
917
|
+
finish(
|
|
918
|
+
new Error(
|
|
919
|
+
`Upload listener closed before ready (code=${code}${reason ? `, reason=${reason}` : ""}).`
|
|
920
|
+
)
|
|
921
|
+
);
|
|
922
|
+
};
|
|
923
|
+
timeoutId = setTimeout(() => {
|
|
924
|
+
finish(new Error(`Timed out waiting ${connectTimeoutMs}ms for upload listener connection.`));
|
|
925
|
+
}, connectTimeoutMs);
|
|
926
|
+
api.listener.on("connected", onConnected);
|
|
927
|
+
api.listener.on("error", onConnectError);
|
|
928
|
+
api.listener.on("closed", onConnectClosed);
|
|
929
|
+
try {
|
|
930
|
+
api.listener.start();
|
|
931
|
+
startedHere = true;
|
|
932
|
+
writeDebugLine(
|
|
933
|
+
"msg.upload.listener.start",
|
|
934
|
+
{
|
|
935
|
+
connectTimeoutMs,
|
|
936
|
+
uploadTimeoutMs
|
|
937
|
+
},
|
|
938
|
+
command
|
|
939
|
+
);
|
|
940
|
+
} catch (error) {
|
|
941
|
+
if (isListenerAlreadyStarted(error)) {
|
|
942
|
+
writeDebugLine("msg.upload.listener.already_started", void 0, command);
|
|
943
|
+
finish();
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
finish(error);
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
return await withTimeout(
|
|
950
|
+
task(),
|
|
951
|
+
uploadTimeoutMs,
|
|
952
|
+
`Timed out waiting ${uploadTimeoutMs}ms for file upload completion.`
|
|
953
|
+
);
|
|
954
|
+
} finally {
|
|
955
|
+
if (startedHere) {
|
|
956
|
+
await stopUploadListenerSafely(api, command);
|
|
957
|
+
}
|
|
958
|
+
api.listener.off("error", sinkError);
|
|
959
|
+
api.listener.off("closed", sinkClosed);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
809
962
|
async function fetchRecentMessagesViaListener(api, threadId, threadType, count) {
|
|
810
963
|
return new Promise((resolve, reject) => {
|
|
811
964
|
let settled = false;
|
|
@@ -2137,13 +2290,17 @@ msg.command("upload <arg1> [arg2]").option("-u, --url <url>", "File URL (repeata
|
|
|
2137
2290
|
);
|
|
2138
2291
|
}
|
|
2139
2292
|
await assertFilesExist(attachments);
|
|
2140
|
-
const response = await
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2293
|
+
const response = await withUploadListener(
|
|
2294
|
+
api,
|
|
2295
|
+
command,
|
|
2296
|
+
async () => api.sendMessage(
|
|
2297
|
+
{
|
|
2298
|
+
msg: "",
|
|
2299
|
+
attachments
|
|
2300
|
+
},
|
|
2301
|
+
threadId,
|
|
2302
|
+
asThreadType(opts.group)
|
|
2303
|
+
)
|
|
2147
2304
|
);
|
|
2148
2305
|
output(response, false);
|
|
2149
2306
|
} finally {
|