ds-harness-remote 0.3.23 → 0.3.24
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 +12 -0
- package/dist/harness-api-bridge.d.ts +23 -3
- package/dist/harness-api-bridge.d.ts.map +1 -1
- package/dist/harness-api-bridge.js +170 -2
- package/dist/harness-api-bridge.js.map +1 -1
- package/dist/index.js +268 -4
- package/dist/index.js.map +2 -2
- package/dist/remote-api-proxy.d.ts +1 -0
- package/dist/remote-api-proxy.d.ts.map +1 -1
- package/dist/remote-api-proxy.js +86 -2
- package/dist/remote-api-proxy.js.map +1 -1
- package/dist/rpc-router.d.ts +1 -1
- package/dist/rpc-router.d.ts.map +1 -1
- package/dist/rpc-router.js +11 -1
- package/dist/rpc-router.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -4052,6 +4052,8 @@ var NEVER = INVALID;
|
|
|
4052
4052
|
var PROTOCOL_VERSION = 1;
|
|
4053
4053
|
var SECURE_FRAGMENT_CHUNK_BYTES = 48 * 1024;
|
|
4054
4054
|
var MAX_SECURE_MESSAGE_BYTES = 4 * 1024 * 1024;
|
|
4055
|
+
var HARNESS_API_TRANSFER_CHUNK_BYTES = 512 * 1024;
|
|
4056
|
+
var MAX_HARNESS_API_TRANSFER_BYTES = 288 * 1024 * 1024;
|
|
4055
4057
|
var SECURE_FRAGMENT_MAGIC = new Uint8Array([68, 83, 72, 70]);
|
|
4056
4058
|
var SECURE_FRAGMENT_VERSION = 1;
|
|
4057
4059
|
var SECURE_FRAGMENT_HEADER_BYTES = 17;
|
|
@@ -4081,6 +4083,11 @@ var controlFrameTypes = [
|
|
|
4081
4083
|
];
|
|
4082
4084
|
var rpcMethods = [
|
|
4083
4085
|
"harness.api.call",
|
|
4086
|
+
"harness.api.transfer.open",
|
|
4087
|
+
"harness.api.transfer.chunk",
|
|
4088
|
+
"harness.api.transfer.commit",
|
|
4089
|
+
"harness.api.transfer.read",
|
|
4090
|
+
"harness.api.transfer.close",
|
|
4084
4091
|
"harness.api.respond",
|
|
4085
4092
|
"harness.api.stream.open",
|
|
4086
4093
|
"harness.api.stream.close",
|
|
@@ -12854,6 +12861,7 @@ function uuidV7(now = Date.now()) {
|
|
|
12854
12861
|
}
|
|
12855
12862
|
|
|
12856
12863
|
// src/remote-api-proxy.ts
|
|
12864
|
+
var DIRECT_API_CALL_BYTES = 2 * 1024 * 1024;
|
|
12857
12865
|
var RemoteHarnessApiProxy = class {
|
|
12858
12866
|
constructor(client) {
|
|
12859
12867
|
this.client = client;
|
|
@@ -12939,16 +12947,76 @@ var RemoteHarnessApiProxy = class {
|
|
|
12939
12947
|
}
|
|
12940
12948
|
api;
|
|
12941
12949
|
async call(method, request, signal) {
|
|
12942
|
-
const
|
|
12950
|
+
const params = {
|
|
12943
12951
|
method,
|
|
12944
12952
|
rpcId: String(request.rpcId),
|
|
12945
12953
|
payload: request.payload
|
|
12946
|
-
}
|
|
12954
|
+
};
|
|
12955
|
+
const encoded = new TextEncoder().encode(JSON.stringify(params));
|
|
12956
|
+
const response = method === "session.attachment" || encoded.byteLength > DIRECT_API_CALL_BYTES ? await this.callTransferred(encoded, signal) : await this.client.rpc("harness.api.call", params, signal);
|
|
12947
12957
|
if (String(response.rpcId) !== String(request.rpcId) || typeof response.result !== "object" || response.result === null) {
|
|
12948
12958
|
throw new Error("The remote Host returned an invalid Harness API response.");
|
|
12949
12959
|
}
|
|
12950
12960
|
return normalizeLegacyResponse(method, response);
|
|
12951
12961
|
}
|
|
12962
|
+
async callTransferred(encoded, signal) {
|
|
12963
|
+
if (encoded.byteLength > MAX_HARNESS_API_TRANSFER_BYTES) {
|
|
12964
|
+
throw new Error("The Harness API request exceeds the remote image transfer limit.");
|
|
12965
|
+
}
|
|
12966
|
+
const transferId = uuidV7();
|
|
12967
|
+
const totalChunks = Math.ceil(encoded.byteLength / HARNESS_API_TRANSFER_CHUNK_BYTES);
|
|
12968
|
+
let opened = false;
|
|
12969
|
+
try {
|
|
12970
|
+
await this.client.rpc("harness.api.transfer.open", {
|
|
12971
|
+
transferId,
|
|
12972
|
+
totalBytes: encoded.byteLength,
|
|
12973
|
+
totalChunks
|
|
12974
|
+
}, signal);
|
|
12975
|
+
opened = true;
|
|
12976
|
+
for (let index = 0; index < totalChunks; index += 1) {
|
|
12977
|
+
const start = index * HARNESS_API_TRANSFER_CHUNK_BYTES;
|
|
12978
|
+
const chunk = encoded.subarray(start, Math.min(start + HARNESS_API_TRANSFER_CHUNK_BYTES, encoded.byteLength));
|
|
12979
|
+
await this.client.rpc("harness.api.transfer.chunk", {
|
|
12980
|
+
transferId,
|
|
12981
|
+
index,
|
|
12982
|
+
data: bytesToBase64(chunk)
|
|
12983
|
+
}, signal);
|
|
12984
|
+
}
|
|
12985
|
+
const committed = await this.client.rpc(
|
|
12986
|
+
"harness.api.transfer.commit",
|
|
12987
|
+
{ transferId },
|
|
12988
|
+
signal
|
|
12989
|
+
);
|
|
12990
|
+
if (committed.kind === "inline") return committed.response;
|
|
12991
|
+
if (committed.transferId !== transferId || committed.totalBytes <= 0 || committed.totalBytes > MAX_HARNESS_API_TRANSFER_BYTES || committed.totalChunks !== Math.ceil(committed.totalBytes / HARNESS_API_TRANSFER_CHUNK_BYTES)) {
|
|
12992
|
+
throw new Error("The remote Host returned an invalid Harness API transfer descriptor.");
|
|
12993
|
+
}
|
|
12994
|
+
const responseBytes = new Uint8Array(committed.totalBytes);
|
|
12995
|
+
let offset = 0;
|
|
12996
|
+
for (let index = 0; index < committed.totalChunks; index += 1) {
|
|
12997
|
+
const result = await this.client.rpc(
|
|
12998
|
+
"harness.api.transfer.read",
|
|
12999
|
+
{ transferId, index },
|
|
13000
|
+
signal
|
|
13001
|
+
);
|
|
13002
|
+
if (result.transferId !== transferId || result.index !== index) {
|
|
13003
|
+
throw new Error("The remote Host returned an out-of-order Harness API transfer chunk.");
|
|
13004
|
+
}
|
|
13005
|
+
const chunk = base64ToBytes(result.data);
|
|
13006
|
+
const expectedBytes = Math.min(HARNESS_API_TRANSFER_CHUNK_BYTES, committed.totalBytes - offset);
|
|
13007
|
+
if (chunk.byteLength !== expectedBytes) {
|
|
13008
|
+
throw new Error("The remote Host returned an invalid Harness API transfer chunk.");
|
|
13009
|
+
}
|
|
13010
|
+
responseBytes.set(chunk, offset);
|
|
13011
|
+
offset += chunk.byteLength;
|
|
13012
|
+
}
|
|
13013
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(responseBytes));
|
|
13014
|
+
} finally {
|
|
13015
|
+
if (opened) {
|
|
13016
|
+
await this.client.rpc("harness.api.transfer.close", { transferId }).catch(() => void 0);
|
|
13017
|
+
}
|
|
13018
|
+
}
|
|
13019
|
+
}
|
|
12952
13020
|
async respond(message) {
|
|
12953
13021
|
return this.client.rpc("harness.api.respond", { message });
|
|
12954
13022
|
}
|
|
@@ -13037,6 +13105,27 @@ function routeStreamEvent(event, streamId, queue) {
|
|
|
13037
13105
|
if (data.streamId === streamId) queue.close();
|
|
13038
13106
|
}
|
|
13039
13107
|
}
|
|
13108
|
+
function bytesToBase64(bytes) {
|
|
13109
|
+
let binary = "";
|
|
13110
|
+
for (let offset = 0; offset < bytes.byteLength; offset += 32768) {
|
|
13111
|
+
binary += String.fromCharCode(...bytes.subarray(offset, Math.min(offset + 32768, bytes.byteLength)));
|
|
13112
|
+
}
|
|
13113
|
+
return btoa(binary);
|
|
13114
|
+
}
|
|
13115
|
+
function base64ToBytes(value) {
|
|
13116
|
+
let binary;
|
|
13117
|
+
try {
|
|
13118
|
+
binary = atob(value);
|
|
13119
|
+
} catch {
|
|
13120
|
+
throw new Error("The remote Host returned a malformed Harness API transfer chunk.");
|
|
13121
|
+
}
|
|
13122
|
+
const bytes = new Uint8Array(binary.length);
|
|
13123
|
+
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
13124
|
+
if (bytesToBase64(bytes) !== value) {
|
|
13125
|
+
throw new Error("The remote Host returned a non-canonical Harness API transfer chunk.");
|
|
13126
|
+
}
|
|
13127
|
+
return bytes;
|
|
13128
|
+
}
|
|
13040
13129
|
|
|
13041
13130
|
// src/server-api.ts
|
|
13042
13131
|
import { platform } from "node:os";
|
|
@@ -13121,7 +13210,7 @@ function normalizeServerUrl(value) {
|
|
|
13121
13210
|
}
|
|
13122
13211
|
|
|
13123
13212
|
// src/version.ts
|
|
13124
|
-
var PLUGIN_VERSION = "0.3.
|
|
13213
|
+
var PLUGIN_VERSION = "0.3.24";
|
|
13125
13214
|
|
|
13126
13215
|
// src/server-api.ts
|
|
13127
13216
|
var HostServerApi = class {
|
|
@@ -14977,12 +15066,17 @@ async function readHarnessDistributionVersion(entrypoint = process.argv[1]) {
|
|
|
14977
15066
|
var wireRequestSchema = external_exports.object({ method: external_exports.string().min(1), params: external_exports.unknown() }).strict();
|
|
14978
15067
|
var apiMethods = /* @__PURE__ */ new Set([
|
|
14979
15068
|
"harness.api.call",
|
|
15069
|
+
"harness.api.transfer.open",
|
|
15070
|
+
"harness.api.transfer.chunk",
|
|
15071
|
+
"harness.api.transfer.commit",
|
|
15072
|
+
"harness.api.transfer.read",
|
|
15073
|
+
"harness.api.transfer.close",
|
|
14980
15074
|
"harness.api.respond",
|
|
14981
15075
|
"harness.api.stream.open",
|
|
14982
15076
|
"harness.api.stream.close",
|
|
14983
15077
|
"fileviewer.call"
|
|
14984
15078
|
]);
|
|
14985
|
-
var HOST_CAPABILITIES = ["harness.api.v1", "fileviewer.read.v1"];
|
|
15079
|
+
var HOST_CAPABILITIES = ["harness.api.v1", "harness.api.transfer.v1", "fileviewer.read.v1"];
|
|
14986
15080
|
var RpcRouter = class {
|
|
14987
15081
|
constructor(harnessApi, maxPending = 128, logger, fileViewer) {
|
|
14988
15082
|
this.harnessApi = harnessApi;
|
|
@@ -15034,6 +15128,16 @@ var RpcRouter = class {
|
|
|
15034
15128
|
switch (method) {
|
|
15035
15129
|
case "harness.api.call":
|
|
15036
15130
|
return this.harnessApi.call(params);
|
|
15131
|
+
case "harness.api.transfer.open":
|
|
15132
|
+
return this.harnessApi.openTransfer(params);
|
|
15133
|
+
case "harness.api.transfer.chunk":
|
|
15134
|
+
return this.harnessApi.appendTransfer(params);
|
|
15135
|
+
case "harness.api.transfer.commit":
|
|
15136
|
+
return this.harnessApi.commitTransfer(params);
|
|
15137
|
+
case "harness.api.transfer.read":
|
|
15138
|
+
return this.harnessApi.readTransfer(params);
|
|
15139
|
+
case "harness.api.transfer.close":
|
|
15140
|
+
return this.harnessApi.closeTransfer(params);
|
|
15037
15141
|
case "harness.api.respond":
|
|
15038
15142
|
return this.harnessApi.respond(params);
|
|
15039
15143
|
case "harness.api.stream.open":
|
|
@@ -15947,6 +16051,20 @@ var streamOpenSchema = external_exports.object({
|
|
|
15947
16051
|
}).strict()
|
|
15948
16052
|
}).strict();
|
|
15949
16053
|
var streamCloseSchema = external_exports.object({ streamId: external_exports.string().min(1).max(128) }).strict();
|
|
16054
|
+
var transferIdSchema = external_exports.string().min(1).max(128);
|
|
16055
|
+
var transferOpenSchema = external_exports.object({
|
|
16056
|
+
transferId: transferIdSchema,
|
|
16057
|
+
totalBytes: external_exports.number().int().positive().max(MAX_HARNESS_API_TRANSFER_BYTES),
|
|
16058
|
+
totalChunks: external_exports.number().int().positive().max(Math.ceil(MAX_HARNESS_API_TRANSFER_BYTES / HARNESS_API_TRANSFER_CHUNK_BYTES))
|
|
16059
|
+
}).strict();
|
|
16060
|
+
var transferChunkSchema = external_exports.object({
|
|
16061
|
+
transferId: transferIdSchema,
|
|
16062
|
+
index: external_exports.number().int().nonnegative(),
|
|
16063
|
+
data: external_exports.string().max(Math.ceil(HARNESS_API_TRANSFER_CHUNK_BYTES / 3) * 4)
|
|
16064
|
+
}).strict();
|
|
16065
|
+
var transferCommitSchema = external_exports.object({ transferId: transferIdSchema }).strict();
|
|
16066
|
+
var transferReadSchema = external_exports.object({ transferId: transferIdSchema, index: external_exports.number().int().nonnegative() }).strict();
|
|
16067
|
+
var transferCloseSchema = external_exports.object({ transferId: transferIdSchema }).strict();
|
|
15950
16068
|
var commandExecuteSchema = external_exports.object({
|
|
15951
16069
|
agentId: external_exports.string().min(1).max(128),
|
|
15952
16070
|
line: external_exports.string().min(1).max(2048)
|
|
@@ -15964,6 +16082,7 @@ var HARNESS_API_ALLOWLIST = [
|
|
|
15964
16082
|
"session.rename",
|
|
15965
16083
|
"session.fork",
|
|
15966
16084
|
"session.prompt",
|
|
16085
|
+
"session.attachment",
|
|
15967
16086
|
"session.updateQueue",
|
|
15968
16087
|
"session.cancel",
|
|
15969
16088
|
"subagent.list",
|
|
@@ -15995,6 +16114,9 @@ var HARNESS_API_ALLOWLIST = [
|
|
|
15995
16114
|
"llm.models"
|
|
15996
16115
|
];
|
|
15997
16116
|
var NATIVE_CALL_TIMEOUT_MS = 3e4;
|
|
16117
|
+
var MAX_ACTIVE_API_TRANSFERS = 2;
|
|
16118
|
+
var API_TRANSFER_IDLE_MS = 2 * 6e4;
|
|
16119
|
+
var INLINE_TRANSFER_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
15998
16120
|
var SESSION_HISTORY_PAGE_SIZES = [50, 30, 20, 12, 6, 3, 1];
|
|
15999
16121
|
var HarnessApiBridge = class {
|
|
16000
16122
|
constructor(api, publish, maxStreams = 8, logger, typertGateway) {
|
|
@@ -16010,6 +16132,8 @@ var HarnessApiBridge = class {
|
|
|
16010
16132
|
methods;
|
|
16011
16133
|
streams = /* @__PURE__ */ new Map();
|
|
16012
16134
|
respondable = /* @__PURE__ */ new Map();
|
|
16135
|
+
incomingTransfers = /* @__PURE__ */ new Map();
|
|
16136
|
+
outgoingTransfers = /* @__PURE__ */ new Map();
|
|
16013
16137
|
mux;
|
|
16014
16138
|
host;
|
|
16015
16139
|
answer;
|
|
@@ -16053,6 +16177,119 @@ var HarnessApiBridge = class {
|
|
|
16053
16177
|
throw error;
|
|
16054
16178
|
}
|
|
16055
16179
|
}
|
|
16180
|
+
openTransfer(input) {
|
|
16181
|
+
this.pruneTransfers();
|
|
16182
|
+
const params = transferOpenSchema.parse(input);
|
|
16183
|
+
if (params.totalChunks !== Math.ceil(params.totalBytes / HARNESS_API_TRANSFER_CHUNK_BYTES)) {
|
|
16184
|
+
throw new RpcError("INVALID_MESSAGE", "The Harness API transfer chunk count is invalid.");
|
|
16185
|
+
}
|
|
16186
|
+
if (this.incomingTransfers.has(params.transferId) || this.outgoingTransfers.has(params.transferId)) {
|
|
16187
|
+
throw new RpcError("REQUEST_CONFLICT", "The Harness API transfer id is already active.");
|
|
16188
|
+
}
|
|
16189
|
+
if (this.incomingTransfers.size >= MAX_ACTIVE_API_TRANSFERS) {
|
|
16190
|
+
throw new RpcError("RATE_LIMITED", "Too many Harness API transfers are active.", void 0, true);
|
|
16191
|
+
}
|
|
16192
|
+
this.incomingTransfers.set(params.transferId, {
|
|
16193
|
+
totalBytes: params.totalBytes,
|
|
16194
|
+
totalChunks: params.totalChunks,
|
|
16195
|
+
chunks: [],
|
|
16196
|
+
receivedBytes: 0,
|
|
16197
|
+
touchedAt: Date.now()
|
|
16198
|
+
});
|
|
16199
|
+
return { opened: true, transferId: params.transferId };
|
|
16200
|
+
}
|
|
16201
|
+
appendTransfer(input) {
|
|
16202
|
+
this.pruneTransfers();
|
|
16203
|
+
const params = transferChunkSchema.parse(input);
|
|
16204
|
+
const transfer = this.incomingTransfers.get(params.transferId);
|
|
16205
|
+
if (transfer === void 0) throw new RpcError("TRANSFER_NOT_FOUND", "The Harness API transfer is not active.");
|
|
16206
|
+
if (params.index !== transfer.chunks.length || params.index >= transfer.totalChunks) {
|
|
16207
|
+
this.incomingTransfers.delete(params.transferId);
|
|
16208
|
+
throw new RpcError("INVALID_MESSAGE", "Harness API transfer chunks must arrive exactly once and in order.");
|
|
16209
|
+
}
|
|
16210
|
+
let chunk;
|
|
16211
|
+
try {
|
|
16212
|
+
chunk = decodeCanonicalBase64(params.data);
|
|
16213
|
+
} catch (error) {
|
|
16214
|
+
this.incomingTransfers.delete(params.transferId);
|
|
16215
|
+
throw error;
|
|
16216
|
+
}
|
|
16217
|
+
const expectedBytes = Math.min(
|
|
16218
|
+
HARNESS_API_TRANSFER_CHUNK_BYTES,
|
|
16219
|
+
transfer.totalBytes - params.index * HARNESS_API_TRANSFER_CHUNK_BYTES
|
|
16220
|
+
);
|
|
16221
|
+
if (chunk.byteLength !== expectedBytes) {
|
|
16222
|
+
this.incomingTransfers.delete(params.transferId);
|
|
16223
|
+
throw new RpcError("INVALID_MESSAGE", "The Harness API transfer chunk size is invalid.");
|
|
16224
|
+
}
|
|
16225
|
+
transfer.chunks.push(chunk);
|
|
16226
|
+
transfer.receivedBytes += chunk.byteLength;
|
|
16227
|
+
transfer.touchedAt = Date.now();
|
|
16228
|
+
return { accepted: true, transferId: params.transferId, index: params.index };
|
|
16229
|
+
}
|
|
16230
|
+
async commitTransfer(input) {
|
|
16231
|
+
this.pruneTransfers();
|
|
16232
|
+
const params = transferCommitSchema.parse(input);
|
|
16233
|
+
const transfer = this.incomingTransfers.get(params.transferId);
|
|
16234
|
+
if (transfer === void 0) throw new RpcError("TRANSFER_NOT_FOUND", "The Harness API transfer is not active.");
|
|
16235
|
+
this.incomingTransfers.delete(params.transferId);
|
|
16236
|
+
if (transfer.chunks.length !== transfer.totalChunks || transfer.receivedBytes !== transfer.totalBytes) {
|
|
16237
|
+
throw new RpcError("INVALID_MESSAGE", "The Harness API transfer is incomplete.");
|
|
16238
|
+
}
|
|
16239
|
+
let request;
|
|
16240
|
+
try {
|
|
16241
|
+
const bytes = concatChunks(transfer.chunks, transfer.totalBytes);
|
|
16242
|
+
request = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
16243
|
+
} catch {
|
|
16244
|
+
throw new RpcError("INVALID_MESSAGE", "The Harness API transfer does not contain a valid request.");
|
|
16245
|
+
}
|
|
16246
|
+
const nativeRequest = callSchema2.parse(request);
|
|
16247
|
+
const response = await this.call(nativeRequest);
|
|
16248
|
+
const responseBytes = new TextEncoder().encode(JSON.stringify(response));
|
|
16249
|
+
if (responseBytes.byteLength <= INLINE_TRANSFER_RESPONSE_BYTES) {
|
|
16250
|
+
return { kind: "inline", response };
|
|
16251
|
+
}
|
|
16252
|
+
if (responseBytes.byteLength > MAX_HARNESS_API_TRANSFER_BYTES) {
|
|
16253
|
+
throw new RpcError("RESPONSE_TOO_LARGE", "The Harness API response exceeds the bounded transfer limit.");
|
|
16254
|
+
}
|
|
16255
|
+
this.pruneTransfers();
|
|
16256
|
+
if (this.outgoingTransfers.size >= MAX_ACTIVE_API_TRANSFERS) {
|
|
16257
|
+
throw new RpcError("RATE_LIMITED", "Too many Harness API response transfers are active.", void 0, true);
|
|
16258
|
+
}
|
|
16259
|
+
const totalChunks = Math.ceil(responseBytes.byteLength / HARNESS_API_TRANSFER_CHUNK_BYTES);
|
|
16260
|
+
this.outgoingTransfers.set(params.transferId, {
|
|
16261
|
+
bytes: responseBytes,
|
|
16262
|
+
totalChunks,
|
|
16263
|
+
nextIndex: 0,
|
|
16264
|
+
touchedAt: Date.now()
|
|
16265
|
+
});
|
|
16266
|
+
return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes.byteLength, totalChunks };
|
|
16267
|
+
}
|
|
16268
|
+
readTransfer(input) {
|
|
16269
|
+
this.pruneTransfers();
|
|
16270
|
+
const params = transferReadSchema.parse(input);
|
|
16271
|
+
const transfer = this.outgoingTransfers.get(params.transferId);
|
|
16272
|
+
if (transfer === void 0) throw new RpcError("TRANSFER_NOT_FOUND", "The Harness API response transfer is not active.");
|
|
16273
|
+
if (params.index !== transfer.nextIndex || params.index >= transfer.totalChunks) {
|
|
16274
|
+
this.outgoingTransfers.delete(params.transferId);
|
|
16275
|
+
throw new RpcError("INVALID_MESSAGE", "Harness API response chunks must be read exactly once and in order.");
|
|
16276
|
+
}
|
|
16277
|
+
const start = params.index * HARNESS_API_TRANSFER_CHUNK_BYTES;
|
|
16278
|
+
const end = Math.min(start + HARNESS_API_TRANSFER_CHUNK_BYTES, transfer.bytes.byteLength);
|
|
16279
|
+
transfer.nextIndex += 1;
|
|
16280
|
+
transfer.touchedAt = Date.now();
|
|
16281
|
+
return {
|
|
16282
|
+
transferId: params.transferId,
|
|
16283
|
+
index: params.index,
|
|
16284
|
+
data: Buffer.from(transfer.bytes.subarray(start, end)).toString("base64")
|
|
16285
|
+
};
|
|
16286
|
+
}
|
|
16287
|
+
closeTransfer(input) {
|
|
16288
|
+
const params = transferCloseSchema.parse(input);
|
|
16289
|
+
const incoming = this.incomingTransfers.delete(params.transferId);
|
|
16290
|
+
const outgoing = this.outgoingTransfers.delete(params.transferId);
|
|
16291
|
+
return { closed: incoming || outgoing, transferId: params.transferId };
|
|
16292
|
+
}
|
|
16056
16293
|
async respond(input) {
|
|
16057
16294
|
const params = respondSchema.parse(input);
|
|
16058
16295
|
this.logger?.debug("harness api respond", { rpcId: shortId4(params.message.rpcId) });
|
|
@@ -16094,8 +16331,19 @@ var HarnessApiBridge = class {
|
|
|
16094
16331
|
const streams = [...this.streams.values()];
|
|
16095
16332
|
this.streams.clear();
|
|
16096
16333
|
this.respondable.clear();
|
|
16334
|
+
this.incomingTransfers.clear();
|
|
16335
|
+
this.outgoingTransfers.clear();
|
|
16097
16336
|
for (const stream of streams) stream.controller.abort(reason);
|
|
16098
16337
|
}
|
|
16338
|
+
pruneTransfers() {
|
|
16339
|
+
const cutoff = Date.now() - API_TRANSFER_IDLE_MS;
|
|
16340
|
+
for (const [transferId, transfer] of this.incomingTransfers) {
|
|
16341
|
+
if (transfer.touchedAt < cutoff) this.incomingTransfers.delete(transferId);
|
|
16342
|
+
}
|
|
16343
|
+
for (const [transferId, transfer] of this.outgoingTransfers) {
|
|
16344
|
+
if (transfer.touchedAt < cutoff) this.outgoingTransfers.delete(transferId);
|
|
16345
|
+
}
|
|
16346
|
+
}
|
|
16099
16347
|
async pump(streamId, stream, signal, focusSessionId) {
|
|
16100
16348
|
let reason = "completed";
|
|
16101
16349
|
try {
|
|
@@ -16270,6 +16518,22 @@ function withTimeout(promise, ms, message) {
|
|
|
16270
16518
|
function shortId4(value) {
|
|
16271
16519
|
return value.length <= 12 ? value : `${value.slice(0, 8)}\u2026${value.slice(-4)}`;
|
|
16272
16520
|
}
|
|
16521
|
+
function decodeCanonicalBase64(value) {
|
|
16522
|
+
const bytes = Buffer.from(value, "base64");
|
|
16523
|
+
if (bytes.toString("base64") !== value) {
|
|
16524
|
+
throw new RpcError("INVALID_MESSAGE", "The Harness API transfer chunk is not canonical base64.");
|
|
16525
|
+
}
|
|
16526
|
+
return bytes;
|
|
16527
|
+
}
|
|
16528
|
+
function concatChunks(chunks, totalBytes) {
|
|
16529
|
+
const result = new Uint8Array(totalBytes);
|
|
16530
|
+
let offset = 0;
|
|
16531
|
+
for (const chunk of chunks) {
|
|
16532
|
+
result.set(chunk, offset);
|
|
16533
|
+
offset += chunk.byteLength;
|
|
16534
|
+
}
|
|
16535
|
+
return result;
|
|
16536
|
+
}
|
|
16273
16537
|
|
|
16274
16538
|
// src/service.ts
|
|
16275
16539
|
var HostPluginRuntime = class {
|