@openclaw/signal 2026.10.2 → 2026.10.5-beta.2
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/.setup/{api-BzvUhsz9.mjs → api-CfFaBHKY.mjs} +8 -8
- package/dist/.setup/{api-BYvpXSbI.mjs → api-oTYg1sqh.mjs} +8 -8
- package/dist/.setup/{approval-handler.runtime-DftlFeEB.mjs → approval-handler.runtime-DzZCg6An.mjs} +2 -3
- package/dist/.setup/{approval-reactions-BHIX1jwY.mjs → approval-reactions-POBtr9RL.mjs} +31 -57
- package/dist/.setup/{channel-E_23H6I6.mjs → channel-v_OVXflu.mjs} +22 -25
- package/dist/.setup/{client-AXcDteBZ.mjs → client-DrPmUInx.mjs} +53 -58
- package/dist/.setup/{client-adapter-c_O1ouxZ.mjs → client-adapter-C25_QRp1.mjs} +1 -1
- package/dist/.setup/{install-signal-cli-ChvjzM6X.mjs → install-signal-cli-hYVLYGXe.mjs} +4 -26
- package/dist/.setup/{monitor-CG20ucVU.mjs → monitor-B2dIc7fW.mjs} +35 -51
- package/dist/.setup/{probe-2LTiStRi.mjs → probe-D6n3Nkud.mjs} +2 -2
- package/dist/.setup/{reaction-runtime-api-xqwxFZ2S.mjs → reaction-runtime-api-BoF_xKQe.mjs} +1 -1
- package/dist/.setup/{reaction-targets-TGHqhdoa.mjs → reaction-targets-Bw8pIemQ.mjs} +1 -1
- package/dist/.setup/{send-CAlJlhsT.mjs → send-Da8lyyyC.mjs} +10 -11
- package/dist/.setup/{setup-surface-BpW9dJZY.mjs → setup-surface-D1IPnECU.mjs} +2 -2
- package/dist/.setup/{transport-detection-CQSEftdN.mjs → transport-detection-C7tIMlYW.mjs} +2 -2
- package/dist/.setup/{transport-probes.runtime-DwXEHnXr.mjs → transport-probes.runtime-CE-YN8v-.mjs} +1 -1
- package/dist/api.js +8 -8
- package/dist/channel-plugin-api.js +1 -1
- package/dist/contract-api.js +2 -2
- package/dist/reaction-runtime-api.js +1 -1
- package/dist/setup-entry.js +1 -1
- package/node_modules/@openclaw/fs-safe/CHANGELOG.md +35 -0
- package/node_modules/@openclaw/fs-safe/README.md +1 -1
- package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/advanced.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/archive-durability.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/archive-merge.js +4 -4
- package/node_modules/@openclaw/fs-safe/dist/archive-parser.wasm +0 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-read.js +5 -4
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.js +22 -38
- package/node_modules/@openclaw/fs-safe/dist/copy-path-admission.d.ts +17 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-path-admission.js +117 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-root-file-sync.d.ts +8 -5
- package/node_modules/@openclaw/fs-safe/dist/copy-root-file-sync.js +27 -50
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-acquire.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-acquire.js +57 -11
- package/node_modules/@openclaw/fs-safe/dist/guarded-mutation.js +5 -5
- package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +52 -5
- package/node_modules/@openclaw/fs-safe/dist/guest.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native-operations.d.ts +0 -1
- package/node_modules/@openclaw/fs-safe/dist/native-operations.js +22 -26
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.js +5 -1
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.js +4 -1
- package/node_modules/@openclaw/fs-safe/dist/permission-exec.js +2 -1
- package/node_modules/@openclaw/fs-safe/dist/pinned-write-types.d.ts +6 -1
- package/node_modules/@openclaw/fs-safe/dist/private-temp-workspace.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/publish-file.js +34 -7
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.js +1 -4
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +6 -0
- package/node_modules/@openclaw/fs-safe/dist/root-create-input.d.ts +15 -1
- package/node_modules/@openclaw/fs-safe/dist/root-create-input.js +4 -0
- package/node_modules/@openclaw/fs-safe/dist/root-directory-entry.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list.d.ts +0 -1
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +6 -12
- package/node_modules/@openclaw/fs-safe/dist/root-impl.js +15 -15
- package/node_modules/@openclaw/fs-safe/dist/root-paths.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/root-walk.js +4 -4
- package/node_modules/@openclaw/fs-safe/dist/root-write-verification.d.ts +10 -1
- package/node_modules/@openclaw/fs-safe/dist/root-write-verification.js +20 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.js +19 -7
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.js +25 -3
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-admission.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-retained.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-retained.js +187 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock.js +15 -1
- package/node_modules/@openclaw/fs-safe/dist/temp-directory-diagnostics.d.ts +10 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-directory-diagnostics.js +29 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-target.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-admission.js +6 -6
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.d.ts +4 -4
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.js +17 -16
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-descriptor.js +20 -28
- package/node_modules/@openclaw/fs-safe/dist/walk.js +2 -13
- package/node_modules/@openclaw/fs-safe/dist/watch-native.d.ts +2 -2
- package/node_modules/@openclaw/fs-safe/dist/watch-native.js +3 -1
- package/node_modules/@openclaw/fs-safe/dist/watch-rescan.js +3 -9
- package/node_modules/@openclaw/fs-safe/dist/watch.js +2 -3
- package/node_modules/@openclaw/fs-safe/docs/advanced.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/archive.md +3 -0
- package/node_modules/@openclaw/fs-safe/docs/atomic.md +11 -3
- package/node_modules/@openclaw/fs-safe/docs/contributing.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/copy.md +48 -0
- package/node_modules/@openclaw/fs-safe/docs/guest.md +21 -4
- package/node_modules/@openclaw/fs-safe/docs/path-scope.md +4 -0
- package/node_modules/@openclaw/fs-safe/docs/sidecar-lock.md +46 -8
- package/node_modules/@openclaw/fs-safe/docs/temp.md +12 -0
- package/node_modules/@openclaw/fs-safe/docs/watch.md +3 -2
- package/node_modules/@openclaw/fs-safe/package.json +15 -15
- package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
- package/node_modules/ws/lib/websocket.js +17 -3
- package/node_modules/ws/package.json +1 -1
- package/package.json +6 -6
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-arbitration.d.ts +0 -17
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-arbitration.js +0 -66
- package/node_modules/@openclaw/fs-safe/dist/publish-file-native.d.ts +0 -4
- package/node_modules/@openclaw/fs-safe/dist/publish-file-native.js +0 -35
- package/node_modules/@openclaw/fs-safe/dist/root-move-preflight.d.ts +0 -7
- package/node_modules/@openclaw/fs-safe/dist/root-move-preflight.js +0 -16
|
@@ -3,14 +3,14 @@ import { i as normalizeSignalTransportHost } from "./transport-url-CAC0JcuI.mjs"
|
|
|
3
3
|
import { i as resolveSignalAccount, o as resolveSignalReplyToMode } from "./accounts-DMtj2E-4.mjs";
|
|
4
4
|
import { n as normalizeSignalMessagingTarget } from "./normalize-D7kSomXt.mjs";
|
|
5
5
|
import { a as normalizeSignalAllowRecipient, c as resolveSignalSender, i as isSignalSenderAllowed, l as looksLikeUuid, n as formatSignalSenderDisplay, o as resolveSignalPeerId, r as formatSignalSenderId, s as resolveSignalRecipient, t as formatSignalPairingIdLine } from "./identity-B3JyPqGO.mjs";
|
|
6
|
-
import { _ as resolveSignalReactionLevel, m as materializeSignalPresentationFallback, p as registerSignalReplyContext, v as formatSignalMediaText, x as isSignalNativeApprovalHandlerConfigured } from "./channel-
|
|
7
|
-
import { a as prepareSignalSocketPath, t as SignalSseRejectionError } from "./client-
|
|
8
|
-
import { n as signalRpcRequest, r as streamSignalEvents, t as signalCheck } from "./client-adapter-
|
|
9
|
-
import { n as sendReactionSignal } from "./reaction-runtime-api-
|
|
6
|
+
import { _ as resolveSignalReactionLevel, m as materializeSignalPresentationFallback, p as registerSignalReplyContext, v as formatSignalMediaText, x as isSignalNativeApprovalHandlerConfigured } from "./channel-v_OVXflu.mjs";
|
|
7
|
+
import { a as prepareSignalSocketPath, t as SignalSseRejectionError } from "./client-DrPmUInx.mjs";
|
|
8
|
+
import { n as signalRpcRequest, r as streamSignalEvents, t as signalCheck } from "./client-adapter-C25_QRp1.mjs";
|
|
9
|
+
import { n as sendReactionSignal } from "./reaction-runtime-api-BoF_xKQe.mjs";
|
|
10
10
|
import { n as getSignalRuntime, t as getOptionalSignalRuntime } from "./runtime-8sxUF217.mjs";
|
|
11
|
-
import { i as maybeResolveSignalApprovalReaction, s as resolveSignalApprovalConversationKey, t as addSignalApprovalReactionHintToStructuredPayload } from "./approval-reactions-
|
|
12
|
-
import { n as registerSignalReactionTargetsForDeliveredPayload, r as maybeResolveSignalQuestionReaction } from "./reaction-targets-
|
|
13
|
-
import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-
|
|
11
|
+
import { i as maybeResolveSignalApprovalReaction, s as resolveSignalApprovalConversationKey, t as addSignalApprovalReactionHintToStructuredPayload } from "./approval-reactions-POBtr9RL.mjs";
|
|
12
|
+
import { n as registerSignalReactionTargetsForDeliveredPayload, r as maybeResolveSignalQuestionReaction } from "./reaction-targets-Bw8pIemQ.mjs";
|
|
13
|
+
import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-Da8lyyyC.mjs";
|
|
14
14
|
import { bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor, createChannelMessageReplyPipeline, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
|
|
15
15
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
16
16
|
import { resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
@@ -18,7 +18,7 @@ import { asPositiveSafeInteger, isRecord, normalizeNullableString, normalizeOpti
|
|
|
18
18
|
import path from "node:path";
|
|
19
19
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
20
20
|
import { normalizeE164, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
21
|
-
import { buildChannelInboundEventContext, buildMentionRegexes, createChannelInboundDebouncer, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundFromLabel, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, logInboundDrop, matchesMentionPatterns, readAgentRunTerminalOutcome,
|
|
21
|
+
import { buildChannelInboundEventContext, buildMentionRegexes, createChannelInboundDebouncer, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundFromLabel, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, logInboundDrop, matchesMentionPatterns, readAgentRunTerminalOutcome, resolveInboundDebounceMs, resolveInboundMentionDecision, resolveInboundSessionEnvelopeContextAsync, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toHistoryMediaEntries, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
|
|
22
22
|
import { canonicalizeBase64, detectMime, estimateBase64DecodedBytes, kindFromMime, saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime";
|
|
23
23
|
import { resolvePromptHistoryLimit } from "openclaw/plugin-sdk/number-runtime";
|
|
24
24
|
import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
@@ -36,13 +36,12 @@ import { waitForTransportReady } from "openclaw/plugin-sdk/transport-ready-runti
|
|
|
36
36
|
import { createInterface } from "node:readline";
|
|
37
37
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
38
38
|
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
39
|
-
import { DEFAULT_EMOJIS,
|
|
39
|
+
import { DEFAULT_EMOJIS, createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
|
|
40
40
|
import { defineStableChannelIngressIdentity, fanInChannelIngressLifecycles } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
41
41
|
import { isControlCommandMessage } from "openclaw/plugin-sdk/command-detection";
|
|
42
42
|
import { createInternalHookEvent, fireAndForgetHook, toInternalMessageReceivedContext, triggerInternalHook } from "openclaw/plugin-sdk/hook-runtime";
|
|
43
43
|
import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
44
44
|
import { resolveBatchedReplyThreadingPolicy } from "openclaw/plugin-sdk/reply-reference";
|
|
45
|
-
import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
46
45
|
import { enqueueSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
47
46
|
import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
|
|
48
47
|
import { listChatCommands, maybeResolveTextAlias, normalizeCommandBody } from "openclaw/plugin-sdk/command-auth-native";
|
|
@@ -77,8 +76,8 @@ async function waitForSignalDaemonReady(params) {
|
|
|
77
76
|
await (params.waitForTransportReadyFn ?? waitForTransportReady)({
|
|
78
77
|
label: "signal daemon",
|
|
79
78
|
timeoutMs: Math.max(0, params.startupDeadlineMs - Date.now()),
|
|
80
|
-
logAfterMs:
|
|
81
|
-
logIntervalMs:
|
|
79
|
+
logAfterMs: 1e4,
|
|
80
|
+
logIntervalMs: 1e4,
|
|
82
81
|
pollIntervalMs: 150,
|
|
83
82
|
abortSignal: params.abortSignal,
|
|
84
83
|
runtime: params.runtime,
|
|
@@ -201,9 +200,7 @@ function spawnSignalDaemon(opts) {
|
|
|
201
200
|
} else error(`signal-cli process error: ${String(err)}`);
|
|
202
201
|
});
|
|
203
202
|
return {
|
|
204
|
-
pid: child.pid ?? void 0,
|
|
205
203
|
exited: exitedPromise,
|
|
206
|
-
isExited: () => exited,
|
|
207
204
|
stop: () => {
|
|
208
205
|
if (exited) return Promise.resolve();
|
|
209
206
|
if (stopPromise) return stopPromise;
|
|
@@ -328,11 +325,6 @@ function normalizeSignalUuidEntry(entry) {
|
|
|
328
325
|
if (lower.startsWith("uuid:")) return signalStripped.slice(5).trim() || null;
|
|
329
326
|
return looksLikeUuid(signalStripped) ? signalStripped : null;
|
|
330
327
|
}
|
|
331
|
-
function normalizeSignalPhoneEntry(entry) {
|
|
332
|
-
const parsed = strippedSignalEntry(entry);
|
|
333
|
-
if (!parsed) return null;
|
|
334
|
-
return normalizeSignalAllowRecipient(parsed.trimmed) ?? null;
|
|
335
|
-
}
|
|
336
328
|
const signalIngressIdentity = defineStableChannelIngressIdentity({
|
|
337
329
|
key: "stable",
|
|
338
330
|
normalizeEntry: () => null,
|
|
@@ -340,7 +332,7 @@ const signalIngressIdentity = defineStableChannelIngressIdentity({
|
|
|
340
332
|
{
|
|
341
333
|
key: "phone",
|
|
342
334
|
kind: "phone",
|
|
343
|
-
normalizeEntry:
|
|
335
|
+
normalizeEntry: (entry) => normalizeSignalAllowRecipient(entry) ?? null,
|
|
344
336
|
normalizeSubject: (value) => value,
|
|
345
337
|
sensitivity: "pii"
|
|
346
338
|
},
|
|
@@ -461,7 +453,7 @@ function resolveSignalInboundConversationKey(accountId, entry) {
|
|
|
461
453
|
}
|
|
462
454
|
function isSignalActiveRunControlText(text) {
|
|
463
455
|
if (isAbortRequestText(text)) return true;
|
|
464
|
-
const normalizedBody = normalizeCommandBody(text
|
|
456
|
+
const normalizedBody = normalizeCommandBody(text);
|
|
465
457
|
const alias = maybeResolveTextAlias(normalizedBody);
|
|
466
458
|
if (!alias) return false;
|
|
467
459
|
const command = listChatCommands().find((entry) => entry.textAliases.some((candidate) => candidate.trim().toLowerCase() === alias));
|
|
@@ -699,7 +691,6 @@ function createSignalEventHandler(deps) {
|
|
|
699
691
|
accountId: deps.accountId,
|
|
700
692
|
groups: resolveChannelGroups(deps.cfg, "signal", deps.accountId)
|
|
701
693
|
});
|
|
702
|
-
const statusReactionTiming = deps.statusReactionTiming ?? DEFAULT_TIMING;
|
|
703
694
|
const activeEnqueueEntries = /* @__PURE__ */ new WeakSet();
|
|
704
695
|
async function handleSignalInboundMessage(entry) {
|
|
705
696
|
const { cfg } = entry;
|
|
@@ -718,10 +709,9 @@ function createSignalEventHandler(deps) {
|
|
|
718
709
|
groupId: entry.groupId,
|
|
719
710
|
senderPeerId: entry.senderPeerId
|
|
720
711
|
});
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
storePath,
|
|
712
|
+
const { envelopeOptions, previousTimestamp } = await resolveInboundSessionEnvelopeContextAsync({
|
|
713
|
+
cfg,
|
|
714
|
+
agentId: route.agentId,
|
|
725
715
|
sessionKey: route.sessionKey
|
|
726
716
|
});
|
|
727
717
|
const body = formatInboundEnvelope({
|
|
@@ -858,7 +848,6 @@ function createSignalEventHandler(deps) {
|
|
|
858
848
|
} },
|
|
859
849
|
initialEmoji: ackReaction,
|
|
860
850
|
emojis: { stallHard: DEFAULT_EMOJIS.stallSoft },
|
|
861
|
-
timing: statusReactionTiming,
|
|
862
851
|
onError: (err) => {
|
|
863
852
|
logAckFailure({
|
|
864
853
|
log: logVerbose,
|
|
@@ -1066,30 +1055,27 @@ function createSignalEventHandler(deps) {
|
|
|
1066
1055
|
await settle();
|
|
1067
1056
|
return;
|
|
1068
1057
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1058
|
+
let inbound = last;
|
|
1059
|
+
if (entries.length > 1) {
|
|
1060
|
+
const combinedText = entries.map((entry) => entry.bodyText).filter(Boolean).join("\n");
|
|
1061
|
+
const combinedCommandBody = entries.map((entry) => entry.commandBody).filter(Boolean).join("\n");
|
|
1062
|
+
if (!combinedText.trim()) {
|
|
1063
|
+
await settle();
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
inbound = {
|
|
1071
1067
|
...last,
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
const combinedText = entries.map((entry) => entry.bodyText).filter(Boolean).join("\n");
|
|
1079
|
-
const combinedCommandBody = entries.map((entry) => entry.commandBody).filter(Boolean).join("\n");
|
|
1080
|
-
if (!combinedText.trim()) {
|
|
1081
|
-
await settle();
|
|
1082
|
-
return;
|
|
1068
|
+
bodyText: combinedText,
|
|
1069
|
+
commandBody: combinedCommandBody,
|
|
1070
|
+
isBatched: true,
|
|
1071
|
+
nativeReplyBody: last.nativeReplyBody ?? last.bodyText,
|
|
1072
|
+
media: entries.flatMap((entry) => entry.media ?? [])
|
|
1073
|
+
};
|
|
1083
1074
|
}
|
|
1084
1075
|
await handleSignalInboundMessage({
|
|
1085
|
-
...
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
turnAdoptionLifecycle: lifecycle,
|
|
1089
|
-
isBatched: true,
|
|
1090
|
-
nativeReplyBody: last.nativeReplyBody ?? last.bodyText,
|
|
1091
|
-
media: entries.flatMap((entry) => entry.media ?? []),
|
|
1092
|
-
channelIngress
|
|
1076
|
+
...inbound,
|
|
1077
|
+
channelIngress,
|
|
1078
|
+
turnAdoptionLifecycle: lifecycle
|
|
1093
1079
|
});
|
|
1094
1080
|
await settle();
|
|
1095
1081
|
}
|
|
@@ -1872,7 +1858,7 @@ async function deliverReplies(params) {
|
|
|
1872
1858
|
} : {}
|
|
1873
1859
|
});
|
|
1874
1860
|
replyPlan.markSent();
|
|
1875
|
-
const messageId =
|
|
1861
|
+
const messageId = result.messageId.trim();
|
|
1876
1862
|
if (messageId) deliveryResults.push({
|
|
1877
1863
|
channel: "signal",
|
|
1878
1864
|
messageId,
|
|
@@ -1992,8 +1978,6 @@ async function monitorSignalProvider(opts = {}) {
|
|
|
1992
1978
|
baseUrl,
|
|
1993
1979
|
abortSignal: daemonLifecycle.abortSignal,
|
|
1994
1980
|
startupDeadlineMs: startupDeadline,
|
|
1995
|
-
logAfterMs: 1e4,
|
|
1996
|
-
logIntervalMs: 1e4,
|
|
1997
1981
|
runtime,
|
|
1998
1982
|
waitForTransportReadyFn
|
|
1999
1983
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { o as __exportAll } from "./doctor-contract-api-CGS80vmV.mjs";
|
|
2
|
-
import { n as signalRpcRequest, t as signalCheck } from "./client-adapter-
|
|
3
|
-
import { t as detectSignalTransport } from "./transport-detection-
|
|
2
|
+
import { n as signalRpcRequest, t as signalCheck } from "./client-adapter-C25_QRp1.mjs";
|
|
3
|
+
import { t as detectSignalTransport } from "./transport-detection-C7tIMlYW.mjs";
|
|
4
4
|
import { normalizeOptionalString, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
5
|
import { runChannelProbe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
6
6
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as resolveSignalAccount } from "./accounts-DMtj2E-4.mjs";
|
|
2
2
|
import { r as normalizeSignalReactionRecipient } from "./normalize-D7kSomXt.mjs";
|
|
3
|
-
import { n as signalRpcRequest } from "./client-adapter-
|
|
3
|
+
import { n as signalRpcRequest } from "./client-adapter-C25_QRp1.mjs";
|
|
4
4
|
import { t as resolveSignalRpcContext } from "./rpc-context-BAXcX7dI.mjs";
|
|
5
5
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
6
6
|
//#region extensions/signal/src/send-reactions.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { o as __exportAll } from "./doctor-contract-api-CGS80vmV.mjs";
|
|
2
2
|
import { i as resolveSignalDeliveredConversationKey } from "./approval-auth-BITw96pZ.mjs";
|
|
3
|
-
import { c as resolveSignalApprovalTargetAuthorKeys, o as registerSignalApprovalReactionTargetForDeliveredPayload } from "./approval-reactions-
|
|
3
|
+
import { c as resolveSignalApprovalTargetAuthorKeys, o as registerSignalApprovalReactionTargetForDeliveredPayload } from "./approval-reactions-POBtr9RL.mjs";
|
|
4
4
|
import { createQuestionReactionTargetStore, questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
5
5
|
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
|
|
6
6
|
//#region extensions/signal/src/question-reactions.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { o as __exportAll } from "./doctor-contract-api-CGS80vmV.mjs";
|
|
2
2
|
import { i as resolveSignalAccount } from "./accounts-DMtj2E-4.mjs";
|
|
3
3
|
import { n as normalizeSignalMessagingTarget } from "./normalize-D7kSomXt.mjs";
|
|
4
|
-
import { p as registerSignalReplyContext, y as markdownToSignalText } from "./channel-
|
|
5
|
-
import { o as isSignalQuoteMetadataRejection } from "./client-
|
|
6
|
-
import { n as signalRpcRequest } from "./client-adapter-
|
|
4
|
+
import { p as registerSignalReplyContext, y as markdownToSignalText } from "./channel-v_OVXflu.mjs";
|
|
5
|
+
import { o as isSignalQuoteMetadataRejection } from "./client-DrPmUInx.mjs";
|
|
6
|
+
import { n as signalRpcRequest } from "./client-adapter-C25_QRp1.mjs";
|
|
7
7
|
import { t as resolveSignalRpcContext } from "./rpc-context-BAXcX7dI.mjs";
|
|
8
8
|
import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
|
|
9
9
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
@@ -33,7 +33,7 @@ function assertSignalRecipientDelivery(result, target) {
|
|
|
33
33
|
if (failures.length === 0 || target.type === "group" && hasSuccessfulRecipient) return;
|
|
34
34
|
throw new Error(`Signal send failed for ${failures.length} recipient${failures.length === 1 ? "" : "s"}: ${[...new Set(failures)].join(", ")}`);
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
function resolveSignalRpcAccountInfo(opts) {
|
|
37
37
|
const cfg = requireRuntimeConfig(opts.cfg, "Signal RPC account resolution");
|
|
38
38
|
return resolveSignalAccount({
|
|
39
39
|
cfg,
|
|
@@ -43,14 +43,13 @@ async function resolveSignalRpcAccountInfo(opts) {
|
|
|
43
43
|
function parseTarget(raw) {
|
|
44
44
|
const value = normalizeSignalMessagingTarget(raw);
|
|
45
45
|
if (!value) throw new Error("Signal recipient is required");
|
|
46
|
-
|
|
47
|
-
if (normalized.startsWith("group:")) return {
|
|
46
|
+
if (value.startsWith("group:")) return {
|
|
48
47
|
type: "group",
|
|
49
|
-
groupId: value.slice(6)
|
|
48
|
+
groupId: value.slice(6)
|
|
50
49
|
};
|
|
51
|
-
if (
|
|
50
|
+
if (value.startsWith("username:")) return {
|
|
52
51
|
type: "username",
|
|
53
|
-
username: value.slice(9)
|
|
52
|
+
username: value.slice(9)
|
|
54
53
|
};
|
|
55
54
|
return {
|
|
56
55
|
type: "recipient",
|
|
@@ -208,7 +207,7 @@ async function sendMessageSignal(to, text, opts) {
|
|
|
208
207
|
};
|
|
209
208
|
}
|
|
210
209
|
async function sendTypingSignal(to, opts) {
|
|
211
|
-
const accountInfo =
|
|
210
|
+
const accountInfo = resolveSignalRpcAccountInfo(opts);
|
|
212
211
|
const { baseUrl, account } = resolveSignalRpcContext(opts, accountInfo);
|
|
213
212
|
const target = parseTarget(to);
|
|
214
213
|
if (target.type === "username") return false;
|
|
@@ -224,7 +223,7 @@ async function sendTypingSignal(to, opts) {
|
|
|
224
223
|
}
|
|
225
224
|
async function sendReadReceiptSignal(to, targetTimestamp, opts) {
|
|
226
225
|
if (!Number.isFinite(targetTimestamp) || targetTimestamp <= 0) return false;
|
|
227
|
-
const accountInfo =
|
|
226
|
+
const accountInfo = resolveSignalRpcAccountInfo(opts);
|
|
228
227
|
const { baseUrl, account } = resolveSignalRpcContext(opts, accountInfo);
|
|
229
228
|
const target = parseTarget(to);
|
|
230
229
|
if (target.type !== "recipient") return false;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as resolveSignalAccount, n as listSignalAccountIds } from "./accounts-DMtj2E-4.mjs";
|
|
2
|
-
import { c as signalNumberTextInput, i as createSignalCliPathTextInput, o as signalCompletionNote, s as signalDmPolicy } from "./channel-
|
|
3
|
-
import { r as installSignalCli } from "./install-signal-cli-
|
|
2
|
+
import { c as signalNumberTextInput, i as createSignalCliPathTextInput, o as signalCompletionNote, s as signalDmPolicy } from "./channel-v_OVXflu.mjs";
|
|
3
|
+
import { r as installSignalCli } from "./install-signal-cli-hYVLYGXe.mjs";
|
|
4
4
|
import { createDetectedBinaryStatus, createSetupTranslator, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
5
5
|
import { detectBinary } from "openclaw/plugin-sdk/setup-tools";
|
|
6
6
|
//#region extensions/signal/src/setup-surface.ts
|
|
@@ -6,10 +6,10 @@ const DEFAULT_PROBE_TIMEOUT_MS = 1e4;
|
|
|
6
6
|
async function detectSignalTransport(params) {
|
|
7
7
|
const url = normalizeSignalTransportUrl(params.url);
|
|
8
8
|
const timeoutMs = params.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
9
|
-
const probes = params.probeNative && params.probeContainer ? void 0 : await import("./transport-probes.runtime-
|
|
9
|
+
const probes = params.probeNative && params.probeContainer ? void 0 : await import("./transport-probes.runtime-CE-YN8v-.mjs");
|
|
10
10
|
const probeNative = params.probeNative ?? probes?.nativeCheck;
|
|
11
11
|
const probeContainer = params.probeContainer ?? probes?.containerCheck;
|
|
12
|
-
if (!probeNative || !probeContainer) throw new Error("Signal transport
|
|
12
|
+
if (!probeNative || !probeContainer) throw new Error("Signal transport checks are unavailable");
|
|
13
13
|
const [native, container] = await Promise.all([probeNative(url, timeoutMs).catch(() => ({ ok: false })), probeContainer(url, timeoutMs, params.account).catch(() => ({ ok: false }))]);
|
|
14
14
|
if (native.ok) return {
|
|
15
15
|
kind: "external-native",
|
package/dist/.setup/{transport-probes.runtime-DwXEHnXr.mjs → transport-probes.runtime-CE-YN8v-.mjs}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as signalCheck, s as containerCheck } from "./client-
|
|
1
|
+
import { n as signalCheck, s as containerCheck } from "./client-DrPmUInx.mjs";
|
|
2
2
|
export { containerCheck, signalCheck as nativeCheck };
|
package/dist/api.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./.setup/accounts-DMtj2E-4.mjs";
|
|
2
2
|
import { n as normalizeSignalMessagingTarget, t as looksLikeSignalTargetId } from "./.setup/normalize-D7kSomXt.mjs";
|
|
3
3
|
import { a as normalizeSignalAllowRecipient, c as resolveSignalSender, i as isSignalSenderAllowed, l as looksLikeUuid, n as formatSignalSenderDisplay, o as resolveSignalPeerId, r as formatSignalSenderId, s as resolveSignalRecipient, t as formatSignalPairingIdLine } from "./.setup/identity-B3JyPqGO.mjs";
|
|
4
|
-
import { _ as resolveSignalReactionLevel, a as normalizeSignalAccountInput, b as markdownToSignalTextChunks, d as probeSignalTransport, f as writeSignalAccountTransport, g as signalMessageActions, h as resolveSignalOutboundTarget, t as signalPlugin, u as prepareSignalManagedNativeTransport, y as markdownToSignalText } from "./.setup/channel-
|
|
5
|
-
import { n as sendReactionSignal, t as removeReactionSignal } from "./.setup/reaction-runtime-api-
|
|
6
|
-
import { t as detectSignalTransport } from "./.setup/transport-detection-
|
|
7
|
-
import { t as signalSetupPlugin } from "./.setup/api-
|
|
8
|
-
import { r as installSignalCli } from "./.setup/install-signal-cli-
|
|
9
|
-
import { t as monitorSignalProvider } from "./.setup/monitor-
|
|
10
|
-
import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./.setup/send-
|
|
11
|
-
import { t as probeSignal } from "./.setup/probe-
|
|
4
|
+
import { _ as resolveSignalReactionLevel, a as normalizeSignalAccountInput, b as markdownToSignalTextChunks, d as probeSignalTransport, f as writeSignalAccountTransport, g as signalMessageActions, h as resolveSignalOutboundTarget, t as signalPlugin, u as prepareSignalManagedNativeTransport, y as markdownToSignalText } from "./.setup/channel-v_OVXflu.mjs";
|
|
5
|
+
import { n as sendReactionSignal, t as removeReactionSignal } from "./.setup/reaction-runtime-api-BoF_xKQe.mjs";
|
|
6
|
+
import { t as detectSignalTransport } from "./.setup/transport-detection-C7tIMlYW.mjs";
|
|
7
|
+
import { t as signalSetupPlugin } from "./.setup/api-oTYg1sqh.mjs";
|
|
8
|
+
import { r as installSignalCli } from "./.setup/install-signal-cli-hYVLYGXe.mjs";
|
|
9
|
+
import { t as monitorSignalProvider } from "./.setup/monitor-B2dIc7fW.mjs";
|
|
10
|
+
import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./.setup/send-Da8lyyyC.mjs";
|
|
11
|
+
import { t as probeSignal } from "./.setup/probe-D6n3Nkud.mjs";
|
|
12
12
|
export { detectSignalTransport, formatSignalPairingIdLine, formatSignalSenderDisplay, formatSignalSenderId, installSignalCli, isSignalSenderAllowed, listEnabledSignalAccounts, listSignalAccountIds, looksLikeSignalTargetId, looksLikeUuid, markdownToSignalText, markdownToSignalTextChunks, monitorSignalProvider, normalizeSignalAccountInput, normalizeSignalAllowRecipient, normalizeSignalMessagingTarget, prepareSignalManagedNativeTransport, probeSignal, probeSignalTransport, removeReactionSignal, resolveDefaultSignalAccountId, resolveSignalAccount, resolveSignalOutboundTarget, resolveSignalPeerId, resolveSignalReactionLevel, resolveSignalRecipient, resolveSignalSender, sendMessageSignal, sendReactionSignal, sendReadReceiptSignal, sendTypingSignal, signalMessageActions, signalPlugin, signalSetupPlugin, writeSignalAccountTransport };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as signalPlugin } from "./.setup/channel-
|
|
1
|
+
import { t as signalPlugin } from "./.setup/channel-v_OVXflu.mjs";
|
|
2
2
|
export { signalPlugin };
|
package/dist/contract-api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { n as normalizeSignalMessagingTarget, r as normalizeSignalReactionRecipient, t as looksLikeSignalTargetId } from "./.setup/normalize-D7kSomXt.mjs";
|
|
2
2
|
import { i as isSignalSenderAllowed } from "./.setup/identity-B3JyPqGO.mjs";
|
|
3
|
-
import {
|
|
4
|
-
export { downloadToFile, extractSignalCliArchive, installSignalCli, installSignalCliFromRelease, isSignalSenderAllowed,
|
|
3
|
+
import { i as installSignalCliFromRelease, n as extractSignalCliArchive, r as installSignalCli, t as downloadToFile } from "./.setup/install-signal-cli-hYVLYGXe.mjs";
|
|
4
|
+
export { downloadToFile, extractSignalCliArchive, installSignalCli, installSignalCliFromRelease, isSignalSenderAllowed, looksLikeSignalTargetId, normalizeSignalMessagingTarget, normalizeSignalReactionRecipient };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as sendReactionSignal, t as removeReactionSignal } from "./.setup/reaction-runtime-api-
|
|
1
|
+
import { n as sendReactionSignal, t as removeReactionSignal } from "./.setup/reaction-runtime-api-BoF_xKQe.mjs";
|
|
2
2
|
export { removeReactionSignal, sendReactionSignal };
|
package/dist/setup-entry.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
var setup_entry_default = defineBundledChannelSetupEntry({
|
|
5
5
|
importMetaUrl: import.meta.url,
|
|
6
6
|
plugin: {
|
|
7
|
-
specifier: fileURLToPath(new URL(".setup/api-
|
|
7
|
+
specifier: fileURLToPath(new URL(".setup/api-CfFaBHKY.mjs", import.meta.url).href),
|
|
8
8
|
exportName: "signalSetupPlugin"
|
|
9
9
|
}
|
|
10
10
|
});
|
|
@@ -2,6 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.25.0 - 2026-10-08
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
|
|
9
|
+
- **Faster synchronous plugin captures:** 16% faster than pre-change main on a measured 6,000-file tree; the new `createRootFileCopyBatchSync` API on `advanced` also reuses directory admissions across copies. ([#878](https://github.com/openclaw/fs-safe/pull/878), [#849](https://github.com/openclaw/fs-safe/pull/849))
|
|
10
|
+
- **Guest workspace publication:** works on gVisor and other Linux filesystems that reject `RENAME_NOREPLACE`. ([#876](https://github.com/openclaw/fs-safe/pull/876))
|
|
11
|
+
- **Root-backed sidecar locks:** native asynchronous release and exit cleanup no longer strand locks after their Root moves. ([#879](https://github.com/openclaw/fs-safe/pull/879))
|
|
12
|
+
- **Guest cross-device moves:** preserve the admitted file permissions. ([#869](https://github.com/openclaw/fs-safe/pull/869))
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- **Guarded copy batches:** `createRootFileCopyBatchSync` on `advanced` reuses directory admissions across synchronous copies on canonical POSIX paths while rechecking ancestor and file identities for every copy; single-file copies also reuse admission within the operation. ([#849](https://github.com/openclaw/fs-safe/pull/849))
|
|
17
|
+
|
|
18
|
+
### Fixes
|
|
19
|
+
|
|
20
|
+
- **Root-backed file locks:** native asynchronous release and exit cleanup follow the created lock's retained identity after its Root moves, preserving replacement files and reporting ownership mismatches. ([#879](https://github.com/openclaw/fs-safe/pull/879)) Thanks @axiom-ncis.
|
|
21
|
+
- **Temp directory diagnostics:** name rejected roots and ancestors, explain ownership, mode, or symlink failures, and provide safe recovery guidance, including for root-run appliances. Thanks @joequant. ([#877](https://github.com/openclaw/fs-safe/pull/877))
|
|
22
|
+
- **Guest directory publication:** publish staged workspaces when Linux filesystems reject `RENAME_NOREPLACE`, with checked file link/unlink fallback and directory rename that can only replace a concurrently created empty directory. ([#876](https://github.com/openclaw/fs-safe/pull/876)) Thanks @valkyriweb.
|
|
23
|
+
- **Guest cross-device moves:** preserve the admitted source file's permissions instead of leaving the destination with a broader default mode. ([#869](https://github.com/openclaw/fs-safe/pull/869))
|
|
24
|
+
- **Move receipts:** publication receipts capture the source identity after synchronous authorization callbacks return, so a source replaced during authorization is reported accurately. ([#868](https://github.com/openclaw/fs-safe/pull/868))
|
|
25
|
+
- **Atomic copy fallback:** report a failed restoration as a failure even when the underlying error carries a restored receipt. ([#851](https://github.com/openclaw/fs-safe/pull/851))
|
|
26
|
+
- **Archive read limits:** keep the validated entry-read byte limit fixed when callers mutate the options during a read. ([#852](https://github.com/openclaw/fs-safe/pull/852))
|
|
27
|
+
- **Watch on macOS:** reconcile notifications for changes to the watched Root itself immediately instead of waiting for the periodic scan. ([#858](https://github.com/openclaw/fs-safe/pull/858))
|
|
28
|
+
- **`pathScope` tilde names:** keep literal `~` directory names inside scoped file and existing-path lookups instead of expanding them. ([#856](https://github.com/openclaw/fs-safe/pull/856))
|
|
29
|
+
|
|
30
|
+
### Performance
|
|
31
|
+
|
|
32
|
+
- **Guarded file copies:** reuse checked canonical POSIX roots during initial path admission, reducing repeated path-resolution work in synchronous plugin source captures without changing per-file identity or race checks.
|
|
33
|
+
- **Root walks:** reuse normalized directory prefixes, cutting a 50k-file walk by 5.6% and its sampled allocation by about 9% while keeping every filesystem and identity check. ([#870](https://github.com/openclaw/fs-safe/pull/870))
|
|
34
|
+
- **Atomic writes:** non-durable async POSIX writes skip a redundant mode change when the staged file already has the requested permissions. ([#871](https://github.com/openclaw/fs-safe/pull/871))
|
|
35
|
+
- **Guarded mutations:** fewer promise allocations around synchronous guard checks, with directory identity checks unchanged. ([#857](https://github.com/openclaw/fs-safe/pull/857))
|
|
36
|
+
- **Archive publication:** fewer promise allocations in archive guard checks, without removing identity or containment checks. ([#864](https://github.com/openclaw/fs-safe/pull/864))
|
|
37
|
+
- **Watch:** Linux and Windows watch passes skip macOS stream-path preparation. ([#860](https://github.com/openclaw/fs-safe/pull/860))
|
|
38
|
+
- **Permission diagnostics:** bound escaping work for large error messages without changing the displayed excerpts. ([#859](https://github.com/openclaw/fs-safe/pull/859))
|
|
39
|
+
|
|
5
40
|
## 0.24.2 - 2026-10-07
|
|
6
41
|
|
|
7
42
|
### Fixes
|
|
@@ -22,7 +22,7 @@ await fs.write("../escape.txt", "x"); // throws FsSafeError("outside-
|
|
|
22
22
|
|
|
23
23
|
That's the whole pitch. `root()` is the product; the rest of the package — JSON stores, atomic writes, secret files, archive extraction, temp workspaces — is supporting cast for the same boundary.
|
|
24
24
|
|
|
25
|
-
Full docs and reference at **[fs-safe.io](https://fs-safe.io)**.
|
|
25
|
+
Full docs and reference at **[fs-safe.io](https://fs-safe.io)**. For synchronous plugin captures, [guarded file copies and batches](docs/copy.md#synchronous-guarded-file-copies) return owned destination descriptors while preserving per-file checks.
|
|
26
26
|
|
|
27
27
|
## Contents
|
|
28
28
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { copyRootFileSync, type CopyRootFileSyncOptions, type CopiedRootFileSync } from "./copy-root-file-sync.js";
|
|
1
|
+
export { copyRootFileSync, createRootFileCopyBatchSync, type RootFileCopyBatchSync, type CopyRootFileSyncOptions, type CopiedRootFileSync } from "./copy-root-file-sync.js";
|
|
2
2
|
export { createAsyncLock } from "./async-lock.js";
|
|
3
3
|
export { createDirectory, createDirectorySync, createFileSync, type CreateDirectoryOptions, type CreateFileOptions, type OwnedFileDescriptorSync, } from "./create.js";
|
|
4
4
|
export { copyFileHandle, copyFileDescriptorSync, type CopyFileHandleOptions } from "./file-handle-transfer.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { copyRootFileSync } from "./copy-root-file-sync.js";
|
|
1
|
+
export { copyRootFileSync, createRootFileCopyBatchSync } from "./copy-root-file-sync.js";
|
|
2
2
|
// Advanced composition surface. These exports are less stable than the focused
|
|
3
3
|
// public subpaths; prefer root/json/store/temp/archive unless you are building a
|
|
4
4
|
// higher-level primitive.
|
|
@@ -65,7 +65,7 @@ export async function finalizeArchivePublication(params) {
|
|
|
65
65
|
const check = () => params.deadline?.check();
|
|
66
66
|
const assertGuards = async (guards) => {
|
|
67
67
|
for (const guard of [params.destinationGuard, ...guards, params.sourceGuard]) {
|
|
68
|
-
|
|
68
|
+
assertDirectoryIdentityGuard(guard);
|
|
69
69
|
check();
|
|
70
70
|
}
|
|
71
71
|
};
|
|
@@ -98,15 +98,15 @@ async function mergeTree(params, publication, durable = true, entryUmask = 0) {
|
|
|
98
98
|
assertSourceDirectory(ancestor);
|
|
99
99
|
};
|
|
100
100
|
const assertGuards = async () => {
|
|
101
|
-
|
|
101
|
+
assertDirectoryIdentityGuard(destinationGuard);
|
|
102
102
|
check();
|
|
103
103
|
for (const ancestor of ancestors) {
|
|
104
|
-
|
|
104
|
+
assertDirectoryIdentityGuard(ancestor.guard);
|
|
105
105
|
check();
|
|
106
106
|
await ancestor.owner.verify(check);
|
|
107
107
|
check();
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
assertDirectoryIdentityGuard(sourceGuard);
|
|
110
110
|
check();
|
|
111
111
|
};
|
|
112
112
|
const walk = async (sourceDir) => {
|
|
@@ -184,7 +184,7 @@ async function mergeTree(params, publication, durable = true, entryUmask = 0) {
|
|
|
184
184
|
await owner.apply(mode, { check, beforeChmod: async () => {
|
|
185
185
|
await assertGuards();
|
|
186
186
|
assertSourceAncestors();
|
|
187
|
-
|
|
187
|
+
assertDirectoryIdentityGuard(guard);
|
|
188
188
|
check();
|
|
189
189
|
await assertResolvedInsideDestination({
|
|
190
190
|
destinationRealDir, targetPath: destinationPath, originalPath,
|
|
Binary file
|
|
@@ -213,7 +213,8 @@ async function readNativeBufferEntry(native, buffer, kind, requested, displayPat
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
export async function readArchiveEntry(archivePath, entryPath, options) {
|
|
216
|
-
|
|
216
|
+
const maxBytes = options.maxBytes;
|
|
217
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {
|
|
217
218
|
throw new RangeError("maxBytes must be a non-negative safe integer");
|
|
218
219
|
}
|
|
219
220
|
const kind = options.kind ?? resolveArchiveKind(archivePath);
|
|
@@ -228,7 +229,7 @@ export async function readArchiveEntry(archivePath, entryPath, options) {
|
|
|
228
229
|
admitZipBuffer(buffer, resolveExtractLimits(), entry => { zipEntries.push(entry); });
|
|
229
230
|
const native = getNativeBinding();
|
|
230
231
|
if (native)
|
|
231
|
-
return await readNativeBufferEntry(native, buffer, kind, requestedEntry, entryPath,
|
|
232
|
-
return kind === "zip" ? await readZipEntry(buffer, requestedEntry,
|
|
233
|
-
: await readTarEntry(buffer, requestedEntry,
|
|
232
|
+
return await readNativeBufferEntry(native, buffer, kind, requestedEntry, entryPath, maxBytes, zipEntries);
|
|
233
|
+
return kind === "zip" ? await readZipEntry(buffer, requestedEntry, maxBytes, zipEntries)
|
|
234
|
+
: await readTarEntry(buffer, requestedEntry, maxBytes, kind);
|
|
234
235
|
}
|
|
@@ -5,7 +5,7 @@ import { ArchiveSecurityError } from "./archive-errors.js";
|
|
|
5
5
|
export type ArchiveDirectoryGuard = AsyncDirectoryGuard<BigIntStats>;
|
|
6
6
|
export declare function createArchiveSymlinkTraversalError(originalPath: string): ArchiveSecurityError;
|
|
7
7
|
export declare function createDirectoryIdentityGuard(dir: string): Promise<ArchiveDirectoryGuard>;
|
|
8
|
-
export declare function assertDirectoryIdentityGuard(guard: ArchiveDirectoryGuard):
|
|
8
|
+
export declare function assertDirectoryIdentityGuard(guard: ArchiveDirectoryGuard): void;
|
|
9
9
|
export declare function prepareArchiveDestinationGuard(destDir: string): Promise<ArchiveDirectoryGuard>;
|
|
10
10
|
export declare function prepareArchiveDestinationDir(destDir: string): Promise<string>;
|
|
11
11
|
export declare function assertResolvedInsideDestination(params: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fsSync, {} from "node:fs";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { assertDirectoryGuard, createAsyncDirectoryGuard, } from "./directory-guard.js";
|
|
5
5
|
import { ownExtractionDestinationMutation, } from "./archive-deadline.js";
|
|
6
6
|
import { ArchiveSecurityError, } from "./archive-errors.js";
|
|
7
7
|
import { FsSafeError } from "./errors.js";
|
|
@@ -38,9 +38,9 @@ export async function createDirectoryIdentityGuard(dir) {
|
|
|
38
38
|
throw err;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
export
|
|
41
|
+
export function assertDirectoryIdentityGuard(guard) {
|
|
42
42
|
try {
|
|
43
|
-
|
|
43
|
+
assertDirectoryGuard(guard, "native");
|
|
44
44
|
}
|
|
45
45
|
catch (err) {
|
|
46
46
|
if (err instanceof FsSafeError || isNotFoundPathError(err)) {
|
|
@@ -200,7 +200,7 @@ async function prepareOutputPath(params, assertGuards, privateWorkingMode = fals
|
|
|
200
200
|
if (existingDestinationGuard && assertGuards)
|
|
201
201
|
await assertGuards();
|
|
202
202
|
else {
|
|
203
|
-
|
|
203
|
+
assertDirectoryIdentityGuard(destinationGuard);
|
|
204
204
|
checkExtractionDeadline(params.deadline);
|
|
205
205
|
await assertGuards?.();
|
|
206
206
|
}
|
|
@@ -213,46 +213,30 @@ async function prepareOutputPath(params, assertGuards, privateWorkingMode = fals
|
|
|
213
213
|
originalPath: params.originalPath,
|
|
214
214
|
});
|
|
215
215
|
checkExtractionDeadline(params.deadline);
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
const relativePath = params.isDirectory ? relPath : path.posix.dirname(relPath);
|
|
217
|
+
if (params.isDirectory || relativePath !== ".") {
|
|
218
|
+
const directoryPath = params.isDirectory ? params.outPath : path.dirname(params.outPath);
|
|
219
|
+
await getFsSafeTestHooks()?.beforeArchiveOutputMutation?.("mkdir", directoryPath);
|
|
218
220
|
checkExtractionDeadline(params.deadline);
|
|
219
221
|
await ownExtractionDestinationMutation(params.deadline, async () => {
|
|
220
222
|
await assertOutputGuards();
|
|
221
223
|
checkExtractionDeadline(params.deadline);
|
|
222
|
-
await mkdirArchiveOutput({
|
|
223
|
-
targetRoot,
|
|
224
|
-
relativePath: relPath,
|
|
225
|
-
originalPath: params.originalPath,
|
|
226
|
-
});
|
|
227
|
-
checkExtractionDeadline(params.deadline);
|
|
228
|
-
await assertDirectoryIdentityGuard(destinationGuard);
|
|
224
|
+
await mkdirArchiveOutput({ targetRoot, relativePath, originalPath: params.originalPath });
|
|
229
225
|
checkExtractionDeadline(params.deadline);
|
|
230
|
-
|
|
231
|
-
destinationRealDir: params.destinationRealDir,
|
|
232
|
-
targetPath: params.outPath,
|
|
233
|
-
originalPath: params.originalPath,
|
|
234
|
-
});
|
|
235
|
-
checkExtractionDeadline(params.deadline);
|
|
236
|
-
});
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
const parentRel = path.posix.dirname(relPath);
|
|
240
|
-
if (parentRel !== ".") {
|
|
241
|
-
await getFsSafeTestHooks()?.beforeArchiveOutputMutation?.("mkdir", path.dirname(params.outPath));
|
|
242
|
-
checkExtractionDeadline(params.deadline);
|
|
243
|
-
await ownExtractionDestinationMutation(params.deadline, async () => {
|
|
244
|
-
await assertOutputGuards();
|
|
245
|
-
checkExtractionDeadline(params.deadline);
|
|
246
|
-
await mkdirArchiveOutput({
|
|
247
|
-
targetRoot,
|
|
248
|
-
relativePath: parentRel,
|
|
249
|
-
originalPath: params.originalPath,
|
|
250
|
-
});
|
|
251
|
-
checkExtractionDeadline(params.deadline);
|
|
252
|
-
await assertDirectoryIdentityGuard(destinationGuard);
|
|
226
|
+
assertDirectoryIdentityGuard(destinationGuard);
|
|
253
227
|
checkExtractionDeadline(params.deadline);
|
|
228
|
+
if (params.isDirectory) {
|
|
229
|
+
await assertResolvedInsideDestination({
|
|
230
|
+
destinationRealDir: params.destinationRealDir,
|
|
231
|
+
targetPath: params.outPath,
|
|
232
|
+
originalPath: params.originalPath,
|
|
233
|
+
});
|
|
234
|
+
checkExtractionDeadline(params.deadline);
|
|
235
|
+
}
|
|
254
236
|
});
|
|
255
237
|
}
|
|
238
|
+
if (params.isDirectory)
|
|
239
|
+
return;
|
|
256
240
|
await assertResolvedInsideDestination({
|
|
257
241
|
destinationRealDir: params.destinationRealDir,
|
|
258
242
|
targetPath: path.dirname(params.outPath),
|
|
@@ -292,12 +276,12 @@ export async function withStagedArchiveDestination(params) {
|
|
|
292
276
|
const stagingGuard = await createDirectoryIdentityGuard(stagingDir);
|
|
293
277
|
try {
|
|
294
278
|
await fs.chmod(stagingDir, ARCHIVE_STAGING_MODE).catch(() => undefined);
|
|
295
|
-
|
|
279
|
+
assertDirectoryIdentityGuard(stagingGuard);
|
|
296
280
|
return await params.run(stagingDir);
|
|
297
281
|
}
|
|
298
282
|
finally {
|
|
299
283
|
try {
|
|
300
|
-
|
|
284
|
+
assertDirectoryIdentityGuard(stagingGuard);
|
|
301
285
|
await fs.rm(stagingDir, { recursive: true, force: true }).catch(() => undefined);
|
|
302
286
|
}
|
|
303
287
|
catch {
|