@mindexec/cli 0.2.45 → 0.2.47
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/package.json +1 -1
- package/remote-hub.js +119 -12
- package/scripts/remote-http-smoke.mjs +54 -0
- package/scripts/remote-hub-smoke.mjs +42 -0
- package/server.js +115 -23
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +31 -14
- package/wwwroot/_framework/MindExecution.Core.xg9yy9l5dz.dll +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.z56elxihok.dll → MindExecution.Kernel.erg96341xf.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.p5cs4ap87v.dll → MindExecution.Plugins.Admin.11j9vpdm9u.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.s35og5uz44.dll → MindExecution.Plugins.Business.oyskf08knn.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.j63qelz8rk.dll → MindExecution.Plugins.Concept.keia4ox68c.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.y74f55e8x3.dll → MindExecution.Plugins.Directory.7pus9p63ym.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.8djc50fh8g.dll → MindExecution.Plugins.PlanMaster.wr3pupzfyo.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.h6y03asuzq.dll → MindExecution.Plugins.YouTube.kpfew1eggc.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.z07jle70qs.dll → MindExecution.Shared.kzibxbai3y.dll} +0 -0
- package/wwwroot/_framework/MindExecution.Web.6fjnkr9ty4.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +21 -21
- package/wwwroot/index.html +3 -3
- package/wwwroot/service-worker-assets.js +24 -24
- package/wwwroot/service-worker.js +1 -1
- package/wwwroot/_framework/MindExecution.Core.6rfnfdndxq.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.gq00wm14q3.dll +0 -0
package/package.json
CHANGED
package/remote-hub.js
CHANGED
|
@@ -19,6 +19,7 @@ const REMOTE_PROTOCOL_VERSION = 1;
|
|
|
19
19
|
const MAX_SYNTHETIC_DEVICES = 1000;
|
|
20
20
|
const DEFAULT_HOST_TARGET_LEASE_MS = 30000;
|
|
21
21
|
const SYNTHETIC_FRAME_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAYAAAD0In+KAAAADElEQVR42mP8z8AAAAMBAQDJ/pLvAAAAAElFTkSuQmCC';
|
|
22
|
+
const SYNTHETIC_FRAME_PAYLOAD = Buffer.from(SYNTHETIC_FRAME_DATA_URL.split(',')[1], 'base64');
|
|
22
23
|
|
|
23
24
|
function isEnabledValue(value, fallback = true) {
|
|
24
25
|
if (value === undefined || value === null || value === '') {
|
|
@@ -122,7 +123,52 @@ function parseJsonLine(line) {
|
|
|
122
123
|
return JSON.parse(text);
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
function
|
|
126
|
+
function createFrameAccessToken() {
|
|
127
|
+
return crypto.randomBytes(18).toString('base64url');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function buildRemoteFramePath(deviceId, frameKind, frame) {
|
|
131
|
+
const token = safeString(frame?.accessToken, 128);
|
|
132
|
+
const frameSeq = Number(frame?.frameSeq);
|
|
133
|
+
if (!deviceId || !token || !Number.isFinite(frameSeq)) {
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const endpoint = frameKind === 'thumbnail' ? 'thumbnail' : 'live/frame';
|
|
138
|
+
const params = new URLSearchParams({
|
|
139
|
+
format: 'binary',
|
|
140
|
+
seq: String(Math.floor(frameSeq)),
|
|
141
|
+
token
|
|
142
|
+
});
|
|
143
|
+
return `/api/remote/devices/${encodeURIComponent(deviceId)}/${endpoint}?${params.toString()}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function serializeRemoteFrame(frame, deviceId, frameKind, options = {}) {
|
|
147
|
+
if (!frame) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const {
|
|
152
|
+
payload,
|
|
153
|
+
accessToken,
|
|
154
|
+
dataUrl,
|
|
155
|
+
...publicFrame
|
|
156
|
+
} = frame;
|
|
157
|
+
|
|
158
|
+
const framePath = buildRemoteFramePath(deviceId, frameKind, frame);
|
|
159
|
+
const serialized = {
|
|
160
|
+
...publicFrame,
|
|
161
|
+
framePath,
|
|
162
|
+
frameUrl: framePath
|
|
163
|
+
};
|
|
164
|
+
if (options.includeDataUrl !== false) {
|
|
165
|
+
serialized.dataUrl = dataUrl;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return serialized;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function serializeDevice(device, options = {}) {
|
|
126
172
|
if (!device) {
|
|
127
173
|
return null;
|
|
128
174
|
}
|
|
@@ -145,8 +191,8 @@ function serializeDevice(device) {
|
|
|
145
191
|
lastDisconnectReason: device.lastDisconnectReason,
|
|
146
192
|
remoteAddress: device.remoteAddress,
|
|
147
193
|
remotePort: device.remotePort,
|
|
148
|
-
latestThumbnail: device.latestThumbnail
|
|
149
|
-
latestLiveFrame: device.latestLiveFrame
|
|
194
|
+
latestThumbnail: serializeRemoteFrame(device.latestThumbnail, device.deviceId, 'thumbnail', options),
|
|
195
|
+
latestLiveFrame: serializeRemoteFrame(device.latestLiveFrame, device.deviceId, 'live', options),
|
|
150
196
|
activeLiveStream: device.activeLiveStream ? { ...device.activeLiveStream } : null,
|
|
151
197
|
latestTask: device.latestTask ? { ...device.latestTask } : null,
|
|
152
198
|
synthetic: device.synthetic === true,
|
|
@@ -376,9 +422,12 @@ export function createRemoteHub(options = {}) {
|
|
|
376
422
|
};
|
|
377
423
|
}
|
|
378
424
|
|
|
379
|
-
function listDevices() {
|
|
425
|
+
function listDevices(options = {}) {
|
|
426
|
+
const serializeOptions = {
|
|
427
|
+
includeDataUrl: options.includeDataUrl !== false
|
|
428
|
+
};
|
|
380
429
|
return [...devices.values()]
|
|
381
|
-
.map(serializeDevice)
|
|
430
|
+
.map(device => serializeDevice(device, serializeOptions))
|
|
382
431
|
.filter(Boolean)
|
|
383
432
|
.sort((a, b) => {
|
|
384
433
|
const nameCompare = String(a.deviceName || '').localeCompare(String(b.deviceName || ''));
|
|
@@ -427,7 +476,10 @@ export function createRemoteHub(options = {}) {
|
|
|
427
476
|
capturedAt: now,
|
|
428
477
|
receivedAt: now,
|
|
429
478
|
byteLength: 68,
|
|
430
|
-
|
|
479
|
+
transport: 'synthetic',
|
|
480
|
+
dataUrl: SYNTHETIC_FRAME_DATA_URL,
|
|
481
|
+
payload: SYNTHETIC_FRAME_PAYLOAD,
|
|
482
|
+
accessToken: createFrameAccessToken()
|
|
431
483
|
};
|
|
432
484
|
}
|
|
433
485
|
|
|
@@ -1095,6 +1147,19 @@ export function createRemoteHub(options = {}) {
|
|
|
1095
1147
|
: `data:${mimeType};base64,${frameData}`;
|
|
1096
1148
|
}
|
|
1097
1149
|
|
|
1150
|
+
function buildFramePayloadBuffer(framePayload, frameData) {
|
|
1151
|
+
if (Buffer.isBuffer(framePayload)) {
|
|
1152
|
+
return Buffer.from(framePayload);
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
const raw = String(frameData || '');
|
|
1156
|
+
const commaIndex = raw.indexOf(',');
|
|
1157
|
+
const base64 = raw.startsWith('data:') && commaIndex >= 0
|
|
1158
|
+
? raw.slice(commaIndex + 1)
|
|
1159
|
+
: raw;
|
|
1160
|
+
return Buffer.from(base64, 'base64');
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1098
1163
|
function applyThumbnailFrame(device, message, framePayload, transport = 'json-base64') {
|
|
1099
1164
|
const frameData = Buffer.isBuffer(framePayload)
|
|
1100
1165
|
? ''
|
|
@@ -1115,6 +1180,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1115
1180
|
|
|
1116
1181
|
const mimeType = safeString(message.mimeType || message.format || 'image/jpeg', 80) || 'image/jpeg';
|
|
1117
1182
|
const capturedAt = safeString(message.capturedAt, 80) || device.lastSeenAt;
|
|
1183
|
+
const payload = buildFramePayloadBuffer(framePayload, frameData);
|
|
1118
1184
|
device.latestThumbnail = {
|
|
1119
1185
|
streamId: safeString(message.streamId, 128) || 'thumbnail',
|
|
1120
1186
|
frameSeq,
|
|
@@ -1127,7 +1193,9 @@ export function createRemoteHub(options = {}) {
|
|
|
1127
1193
|
receivedAt: device.lastSeenAt,
|
|
1128
1194
|
byteLength,
|
|
1129
1195
|
transport,
|
|
1130
|
-
dataUrl: buildFrameDataUrl(framePayload, frameData, mimeType)
|
|
1196
|
+
dataUrl: buildFrameDataUrl(framePayload, frameData, mimeType),
|
|
1197
|
+
payload,
|
|
1198
|
+
accessToken: createFrameAccessToken()
|
|
1131
1199
|
};
|
|
1132
1200
|
device.counters.thumbnailFramesReceived += 1;
|
|
1133
1201
|
emitRemoteEvent('RemoteFrameReceived', device, {
|
|
@@ -1173,6 +1241,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1173
1241
|
|
|
1174
1242
|
const mimeType = safeString(message.mimeType || message.format || 'image/jpeg', 80) || 'image/jpeg';
|
|
1175
1243
|
const capturedAt = safeString(message.capturedAt, 80) || device.lastSeenAt;
|
|
1244
|
+
const payload = buildFramePayloadBuffer(framePayload, frameData);
|
|
1176
1245
|
device.latestLiveFrame = {
|
|
1177
1246
|
streamId,
|
|
1178
1247
|
frameSeq,
|
|
@@ -1187,7 +1256,9 @@ export function createRemoteHub(options = {}) {
|
|
|
1187
1256
|
receivedAt: device.lastSeenAt,
|
|
1188
1257
|
byteLength,
|
|
1189
1258
|
transport,
|
|
1190
|
-
dataUrl: buildFrameDataUrl(framePayload, frameData, mimeType)
|
|
1259
|
+
dataUrl: buildFrameDataUrl(framePayload, frameData, mimeType),
|
|
1260
|
+
payload,
|
|
1261
|
+
accessToken: createFrameAccessToken()
|
|
1191
1262
|
};
|
|
1192
1263
|
device.activeLiveStream.lastFrameAt = device.lastSeenAt;
|
|
1193
1264
|
device.activeLiveStream.lastFrameSeq = frameSeq;
|
|
@@ -1904,14 +1975,49 @@ export function createRemoteHub(options = {}) {
|
|
|
1904
1975
|
return { ok: true, commandId, streamId };
|
|
1905
1976
|
}
|
|
1906
1977
|
|
|
1907
|
-
function getDeviceLiveFrame(deviceId) {
|
|
1978
|
+
function getDeviceLiveFrame(deviceId, options = {}) {
|
|
1908
1979
|
const device = devices.get(String(deviceId || ''));
|
|
1909
|
-
return device?.latestLiveFrame
|
|
1980
|
+
return serializeRemoteFrame(device?.latestLiveFrame, device?.deviceId, 'live', {
|
|
1981
|
+
includeDataUrl: options.includeDataUrl !== false
|
|
1982
|
+
});
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
function getDeviceThumbnail(deviceId, options = {}) {
|
|
1986
|
+
const device = devices.get(String(deviceId || ''));
|
|
1987
|
+
return serializeRemoteFrame(device?.latestThumbnail, device?.deviceId, 'thumbnail', {
|
|
1988
|
+
includeDataUrl: options.includeDataUrl !== false
|
|
1989
|
+
});
|
|
1910
1990
|
}
|
|
1911
1991
|
|
|
1912
|
-
function
|
|
1992
|
+
function getFramePayload(deviceId, frameKind, options = {}) {
|
|
1913
1993
|
const device = devices.get(String(deviceId || ''));
|
|
1914
|
-
|
|
1994
|
+
const frame = frameKind === 'thumbnail'
|
|
1995
|
+
? device?.latestThumbnail
|
|
1996
|
+
: device?.latestLiveFrame;
|
|
1997
|
+
if (!frame || !Buffer.isBuffer(frame.payload)) {
|
|
1998
|
+
return null;
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
const requestedSeq = Number(options.frameSeq);
|
|
2002
|
+
if (Number.isFinite(requestedSeq) && Math.floor(requestedSeq) !== frame.frameSeq) {
|
|
2003
|
+
return null;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
const token = safeString(options.token, 128);
|
|
2007
|
+
if (token && !timingSafeStringEqual(token, frame.accessToken)) {
|
|
2008
|
+
return null;
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
if (options.requireToken === true && !token) {
|
|
2012
|
+
return null;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
return {
|
|
2016
|
+
frame: serializeRemoteFrame(frame, device.deviceId, frameKind, { includeDataUrl: false }),
|
|
2017
|
+
payload: frame.payload,
|
|
2018
|
+
mimeType: safeString(frame.mimeType || frame.format || 'application/octet-stream', 120) || 'application/octet-stream',
|
|
2019
|
+
byteLength: frame.payload.length
|
|
2020
|
+
};
|
|
1915
2021
|
}
|
|
1916
2022
|
|
|
1917
2023
|
return {
|
|
@@ -1931,6 +2037,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1931
2037
|
stopLiveStream,
|
|
1932
2038
|
getDeviceLiveFrame,
|
|
1933
2039
|
getDeviceThumbnail,
|
|
2040
|
+
getFramePayload,
|
|
1934
2041
|
seedSyntheticFleet,
|
|
1935
2042
|
clearSyntheticFleet,
|
|
1936
2043
|
getPairToken: () => pairToken
|
|
@@ -54,6 +54,26 @@ async function fetchJson(url, options = {}) {
|
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
async function fetchBinary(url, options = {}) {
|
|
58
|
+
const response = await fetch(url, {
|
|
59
|
+
...options,
|
|
60
|
+
headers: {
|
|
61
|
+
Accept: 'image/png,image/jpeg,image/webp,image/*',
|
|
62
|
+
...(options.token ? { 'X-Bridge-Token': options.token } : {}),
|
|
63
|
+
...(options.headers || {})
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
status: response.status,
|
|
69
|
+
ok: response.ok,
|
|
70
|
+
contentType: response.headers.get('content-type') || '',
|
|
71
|
+
frameSeq: response.headers.get('x-mindexec-remote-frame-seq') || '',
|
|
72
|
+
streamId: response.headers.get('x-mindexec-remote-stream-id') || '',
|
|
73
|
+
payload: Buffer.from(await response.arrayBuffer())
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
57
77
|
async function waitForBridge(baseUrl, getFailureDetails, bridgeToken = BRIDGE_TOKEN) {
|
|
58
78
|
const startedAt = Date.now();
|
|
59
79
|
while (Date.now() - startedAt < 30000) {
|
|
@@ -339,6 +359,23 @@ async function runSyntheticEnabledSmoke() {
|
|
|
339
359
|
assert.equal(thumbnail.ok, true, JSON.stringify(thumbnail.payload));
|
|
340
360
|
assert.equal(thumbnail.payload?.thumbnail?.streamId, 'http-smoke-thumb');
|
|
341
361
|
assert.ok(String(thumbnail.payload?.thumbnail?.dataUrl || '').startsWith('data:image/png;base64,'));
|
|
362
|
+
assert.ok(String(thumbnail.payload?.thumbnail?.framePath || '').includes(`/api/remote/devices/${encodeURIComponent(thumbnailTarget.deviceId)}/thumbnail?`));
|
|
363
|
+
assert.equal(thumbnail.payload?.thumbnail?.frameUrl, thumbnail.payload?.thumbnail?.framePath);
|
|
364
|
+
|
|
365
|
+
const thumbnailBinary = await fetchBinary(`${baseUrl}${thumbnail.payload.thumbnail.framePath}`);
|
|
366
|
+
assert.equal(thumbnailBinary.ok, true, `${thumbnailBinary.status} ${thumbnailBinary.contentType}`);
|
|
367
|
+
assert.equal(thumbnailBinary.contentType, 'image/png');
|
|
368
|
+
assert.equal(thumbnailBinary.streamId, 'http-smoke-thumb');
|
|
369
|
+
assert.ok(thumbnailBinary.payload.length > 0);
|
|
370
|
+
|
|
371
|
+
const badThumbnailBinary = await fetchBinary(`${baseUrl}${thumbnail.payload.thumbnail.framePath.replace(/token=[^&]+/, 'token=wrong-token')}`);
|
|
372
|
+
assert.equal(badThumbnailBinary.status, 401);
|
|
373
|
+
|
|
374
|
+
const devicesUrlOnlyResult = await fetchJson(`${baseUrl}/api/remote/devices?frameData=url`, { token: BRIDGE_TOKEN });
|
|
375
|
+
assert.equal(devicesUrlOnlyResult.ok, true, JSON.stringify(devicesUrlOnlyResult.payload));
|
|
376
|
+
const urlOnlyThumbnailDevice = devicesUrlOnlyResult.payload?.devices?.find(device => device.deviceId === thumbnailTarget.deviceId);
|
|
377
|
+
assert.ok(urlOnlyThumbnailDevice?.latestThumbnail?.framePath);
|
|
378
|
+
assert.ok(!('dataUrl' in urlOnlyThumbnailDevice.latestThumbnail));
|
|
342
379
|
|
|
343
380
|
const liveTarget = devicesResult.payload.devices.find(device =>
|
|
344
381
|
device.connected && device.capabilities?.liveStream);
|
|
@@ -364,6 +401,23 @@ async function runSyntheticEnabledSmoke() {
|
|
|
364
401
|
assert.equal(liveFrame.payload?.frame?.streamId, 'http-smoke-live');
|
|
365
402
|
assert.equal(liveFrame.payload?.frame?.mode, 'remote-fast');
|
|
366
403
|
assert.equal(liveFrame.payload?.frame?.fps, 20);
|
|
404
|
+
assert.ok(String(liveFrame.payload?.frame?.dataUrl || '').startsWith('data:image/png;base64,'));
|
|
405
|
+
assert.ok(String(liveFrame.payload?.frame?.framePath || '').includes(`/api/remote/devices/${encodeURIComponent(liveTarget.deviceId)}/live/frame?`));
|
|
406
|
+
|
|
407
|
+
const liveBinary = await fetchBinary(`${baseUrl}${liveFrame.payload.frame.framePath}`);
|
|
408
|
+
assert.equal(liveBinary.ok, true, `${liveBinary.status} ${liveBinary.contentType}`);
|
|
409
|
+
assert.equal(liveBinary.contentType, 'image/png');
|
|
410
|
+
assert.equal(liveBinary.streamId, 'http-smoke-live');
|
|
411
|
+
assert.ok(liveBinary.payload.length > 0);
|
|
412
|
+
|
|
413
|
+
const liveBinaryWithBridgeToken = await fetchBinary(
|
|
414
|
+
`${baseUrl}/api/remote/devices/${encodeURIComponent(liveTarget.deviceId)}/live/frame?format=binary`,
|
|
415
|
+
{ token: BRIDGE_TOKEN });
|
|
416
|
+
assert.equal(liveBinaryWithBridgeToken.ok, true, `${liveBinaryWithBridgeToken.status} ${liveBinaryWithBridgeToken.contentType}`);
|
|
417
|
+
assert.equal(liveBinaryWithBridgeToken.contentType, 'image/png');
|
|
418
|
+
|
|
419
|
+
const badLiveSeq = await fetchBinary(`${baseUrl}${liveFrame.payload.frame.framePath.replace(/seq=\d+/, 'seq=999999')}`);
|
|
420
|
+
assert.equal(badLiveSeq.status, 401);
|
|
367
421
|
|
|
368
422
|
const liveStop = await fetchJson(`${baseUrl}/api/remote/devices/${encodeURIComponent(liveTarget.deviceId)}/live/stop`, {
|
|
369
423
|
method: 'POST',
|
|
@@ -152,6 +152,27 @@ try {
|
|
|
152
152
|
assert.equal(binaryThumbnailDevice.latestThumbnail.transport, 'binary');
|
|
153
153
|
assert.equal(binaryThumbnailDevice.latestThumbnail.byteLength, smokePngFrame.length);
|
|
154
154
|
assert.equal(binaryThumbnailDevice.counters.thumbnailFramesReceived, 2);
|
|
155
|
+
const serializedBinaryThumbnail = hub.getDeviceThumbnail('smoke-device', { includeDataUrl: false });
|
|
156
|
+
assert.equal(serializedBinaryThumbnail.streamId, 'smoke-thumb-binary');
|
|
157
|
+
assert.equal(serializedBinaryThumbnail.frameSeq, 4);
|
|
158
|
+
assert.ok(serializedBinaryThumbnail.framePath.includes('/api/remote/devices/smoke-device/thumbnail?'));
|
|
159
|
+
assert.ok(!('dataUrl' in serializedBinaryThumbnail));
|
|
160
|
+
assert.ok(!('payload' in serializedBinaryThumbnail));
|
|
161
|
+
assert.ok(!('accessToken' in serializedBinaryThumbnail));
|
|
162
|
+
const serializedThumbnailUrl = new URL(serializedBinaryThumbnail.framePath, 'http://127.0.0.1');
|
|
163
|
+
const thumbnailPayload = hub.getFramePayload('smoke-device', 'thumbnail', {
|
|
164
|
+
token: serializedThumbnailUrl.searchParams.get('token'),
|
|
165
|
+
frameSeq: serializedThumbnailUrl.searchParams.get('seq'),
|
|
166
|
+
requireToken: true
|
|
167
|
+
});
|
|
168
|
+
assert.equal(thumbnailPayload?.mimeType, 'image/png');
|
|
169
|
+
assert.equal(thumbnailPayload?.byteLength, smokePngFrame.length);
|
|
170
|
+
assert.equal(Buffer.compare(thumbnailPayload.payload, smokePngFrame), 0);
|
|
171
|
+
assert.equal(hub.getFramePayload('smoke-device', 'thumbnail', {
|
|
172
|
+
token: 'wrong-token',
|
|
173
|
+
frameSeq: 4,
|
|
174
|
+
requireToken: true
|
|
175
|
+
}), null);
|
|
155
176
|
|
|
156
177
|
const liveCommand = hub.startLiveStream('smoke-device', {
|
|
157
178
|
streamId: 'smoke-live',
|
|
@@ -204,6 +225,27 @@ try {
|
|
|
204
225
|
assert.equal(binaryLiveDevice.latestLiveFrame.transport, 'binary');
|
|
205
226
|
assert.equal(binaryLiveDevice.latestLiveFrame.byteLength, smokePngFrame.length);
|
|
206
227
|
assert.equal(binaryLiveDevice.counters.liveFramesReceived, 2);
|
|
228
|
+
const serializedBinaryLiveFrame = hub.getDeviceLiveFrame('smoke-device', { includeDataUrl: false });
|
|
229
|
+
assert.equal(serializedBinaryLiveFrame.streamId, 'smoke-live');
|
|
230
|
+
assert.equal(serializedBinaryLiveFrame.frameSeq, 5);
|
|
231
|
+
assert.ok(serializedBinaryLiveFrame.framePath.includes('/api/remote/devices/smoke-device/live/frame?'));
|
|
232
|
+
assert.ok(!('dataUrl' in serializedBinaryLiveFrame));
|
|
233
|
+
assert.ok(!('payload' in serializedBinaryLiveFrame));
|
|
234
|
+
assert.ok(!('accessToken' in serializedBinaryLiveFrame));
|
|
235
|
+
const serializedLiveUrl = new URL(serializedBinaryLiveFrame.framePath, 'http://127.0.0.1');
|
|
236
|
+
const livePayload = hub.getFramePayload('smoke-device', 'live', {
|
|
237
|
+
token: serializedLiveUrl.searchParams.get('token'),
|
|
238
|
+
frameSeq: serializedLiveUrl.searchParams.get('seq'),
|
|
239
|
+
requireToken: true
|
|
240
|
+
});
|
|
241
|
+
assert.equal(livePayload?.mimeType, 'image/png');
|
|
242
|
+
assert.equal(livePayload?.byteLength, smokePngFrame.length);
|
|
243
|
+
assert.equal(Buffer.compare(livePayload.payload, smokePngFrame), 0);
|
|
244
|
+
assert.equal(hub.getFramePayload('smoke-device', 'live', {
|
|
245
|
+
token: serializedLiveUrl.searchParams.get('token'),
|
|
246
|
+
frameSeq: 4,
|
|
247
|
+
requireToken: true
|
|
248
|
+
}), null);
|
|
207
249
|
|
|
208
250
|
const staleFrameBefore = liveDevice.counters.liveFramesDropped;
|
|
209
251
|
writeJsonLine(socket, {
|
package/server.js
CHANGED
|
@@ -1756,20 +1756,69 @@ const PROTECTED_BRIDGE_ROUTES = [
|
|
|
1756
1756
|
{ method: 'POST', exact: '/api/tool/trace' }
|
|
1757
1757
|
];
|
|
1758
1758
|
|
|
1759
|
-
function getBridgeTokenFromRequest(req) {
|
|
1760
|
-
const headerToken = String(req.get(bridgeTokenHeader) || '').trim();
|
|
1761
|
-
if (headerToken) {
|
|
1762
|
-
return headerToken;
|
|
1763
|
-
}
|
|
1759
|
+
function getBridgeTokenFromRequest(req) {
|
|
1760
|
+
const headerToken = String(req.get(bridgeTokenHeader) || '').trim();
|
|
1761
|
+
if (headerToken) {
|
|
1762
|
+
return headerToken;
|
|
1763
|
+
}
|
|
1764
1764
|
|
|
1765
1765
|
const authorization = String(req.get('authorization') || '').trim();
|
|
1766
|
-
const bearerMatch = authorization.match(/^Bearer\s+(.+)$/i);
|
|
1767
|
-
return bearerMatch ? bearerMatch[1].trim() : '';
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
|
-
function
|
|
1771
|
-
|
|
1772
|
-
|
|
1766
|
+
const bearerMatch = authorization.match(/^Bearer\s+(.+)$/i);
|
|
1767
|
+
return bearerMatch ? bearerMatch[1].trim() : '';
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
function isBridgeTokenAuthorized(req) {
|
|
1771
|
+
return !bridgeAuthRequired || getBridgeTokenFromRequest(req) === bridgeToken;
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
function wantsRemoteFrameBinaryRequest(req) {
|
|
1775
|
+
const format = String(req.query?.format || req.query?.frameData || '').trim().toLowerCase();
|
|
1776
|
+
if (format === 'binary' || format === 'image' || format === 'raw') {
|
|
1777
|
+
return true;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
const accept = String(req.get('accept') || '').toLowerCase();
|
|
1781
|
+
return /\bimage\//.test(accept) && !accept.includes('application/json');
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
function getRemoteFrameTokenRequest(req) {
|
|
1785
|
+
if (String(req.method || '').toUpperCase() !== 'GET' || !wantsRemoteFrameBinaryRequest(req)) {
|
|
1786
|
+
return null;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
const match = String(req.path || '').match(/^\/api\/remote\/devices\/([^/]+)\/(thumbnail|live\/frame)$/i);
|
|
1790
|
+
if (!match) {
|
|
1791
|
+
return null;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
try {
|
|
1795
|
+
return {
|
|
1796
|
+
deviceId: decodeURIComponent(match[1]),
|
|
1797
|
+
frameKind: match[2].toLowerCase() === 'thumbnail' ? 'thumbnail' : 'live',
|
|
1798
|
+
token: String(req.query?.token || '').trim(),
|
|
1799
|
+
frameSeq: req.query?.seq
|
|
1800
|
+
};
|
|
1801
|
+
} catch {
|
|
1802
|
+
return null;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
function isAuthorizedRemoteFrameTokenRequest(req) {
|
|
1807
|
+
const frameRequest = getRemoteFrameTokenRequest(req);
|
|
1808
|
+
if (!frameRequest?.token) {
|
|
1809
|
+
return false;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
return !!remoteHub.getFramePayload(frameRequest.deviceId, frameRequest.frameKind, {
|
|
1813
|
+
token: frameRequest.token,
|
|
1814
|
+
frameSeq: frameRequest.frameSeq,
|
|
1815
|
+
requireToken: true
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
function isProtectedBridgeRoute(method, requestPath) {
|
|
1820
|
+
const normalizedMethod = String(method || '').toUpperCase();
|
|
1821
|
+
const normalizedPath = String(requestPath || '').toLowerCase();
|
|
1773
1822
|
|
|
1774
1823
|
return PROTECTED_BRIDGE_ROUTES.some((rule) => {
|
|
1775
1824
|
if (rule.method && rule.method !== normalizedMethod) {
|
|
@@ -1786,13 +1835,13 @@ function isProtectedBridgeRoute(method, requestPath) {
|
|
|
1786
1835
|
|
|
1787
1836
|
return false;
|
|
1788
1837
|
});
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
function requireBridgeToken(req, res, next) {
|
|
1792
|
-
if (
|
|
1793
|
-
next();
|
|
1794
|
-
return;
|
|
1795
|
-
}
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
function requireBridgeToken(req, res, next) {
|
|
1841
|
+
if (isBridgeTokenAuthorized(req) || isAuthorizedRemoteFrameTokenRequest(req)) {
|
|
1842
|
+
next();
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1796
1845
|
|
|
1797
1846
|
res.status(401).json({
|
|
1798
1847
|
error: 'Bridge token required',
|
|
@@ -6967,7 +7016,8 @@ app.get('/api/remote/status', (req, res) => {
|
|
|
6967
7016
|
|
|
6968
7017
|
app.get('/api/remote/devices', (req, res) => {
|
|
6969
7018
|
res.setHeader('Cache-Control', 'no-store');
|
|
6970
|
-
const
|
|
7019
|
+
const includeDataUrl = !/^(0|false|no|url|metadata)$/i.test(String(req.query?.includeDataUrl ?? req.query?.frameData ?? ''));
|
|
7020
|
+
const devices = remoteHub.listDevices({ includeDataUrl });
|
|
6971
7021
|
res.json({
|
|
6972
7022
|
total: devices.length,
|
|
6973
7023
|
pagination: 'none',
|
|
@@ -7058,7 +7108,7 @@ app.post('/api/remote/tasks', (req, res) => {
|
|
|
7058
7108
|
: [];
|
|
7059
7109
|
const allConnected = req.body?.allConnected !== false;
|
|
7060
7110
|
const approvalLevel = req.body?.approvalLevel === 'ai-assist' ? 'ai-assist' : 'task-only';
|
|
7061
|
-
const devices = remoteHub.listDevices();
|
|
7111
|
+
const devices = remoteHub.listDevices({ includeDataUrl: false });
|
|
7062
7112
|
const targetIds = requestedDeviceIds.length > 0
|
|
7063
7113
|
? requestedDeviceIds
|
|
7064
7114
|
: (allConnected
|
|
@@ -7098,9 +7148,44 @@ function isRemoteCapabilityEnabled(device, key) {
|
|
|
7098
7148
|
return /^(1|true|yes|on)$/i.test(String(value || '').trim());
|
|
7099
7149
|
}
|
|
7100
7150
|
|
|
7151
|
+
function includeRemoteFrameDataUrl(req) {
|
|
7152
|
+
return !/^(0|false|no|url|metadata)$/i.test(String(req.query?.includeDataUrl ?? req.query?.frameData ?? ''));
|
|
7153
|
+
}
|
|
7154
|
+
|
|
7155
|
+
function sendRemoteFrameBinary(req, res, frameKind) {
|
|
7156
|
+
const bridgeAuthorized = isBridgeTokenAuthorized(req);
|
|
7157
|
+
const payload = remoteHub.getFramePayload(req.params.deviceId, frameKind, {
|
|
7158
|
+
token: bridgeAuthorized ? '' : req.query?.token,
|
|
7159
|
+
frameSeq: req.query?.seq,
|
|
7160
|
+
requireToken: !bridgeAuthorized
|
|
7161
|
+
});
|
|
7162
|
+
if (!payload) {
|
|
7163
|
+
res.status(bridgeAuthorized ? 404 : 403).json({
|
|
7164
|
+
ok: false,
|
|
7165
|
+
error: bridgeAuthorized ? 'frame-payload-not-available' : 'invalid-frame-token'
|
|
7166
|
+
});
|
|
7167
|
+
return true;
|
|
7168
|
+
}
|
|
7169
|
+
|
|
7170
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
7171
|
+
res.setHeader('Content-Type', payload.mimeType);
|
|
7172
|
+
res.setHeader('Content-Length', String(payload.byteLength));
|
|
7173
|
+
res.setHeader('X-MindExec-Remote-Frame-Seq', String(payload.frame?.frameSeq || ''));
|
|
7174
|
+
res.setHeader('X-MindExec-Remote-Stream-Id', String(payload.frame?.streamId || ''));
|
|
7175
|
+
res.send(payload.payload);
|
|
7176
|
+
return true;
|
|
7177
|
+
}
|
|
7178
|
+
|
|
7101
7179
|
app.get('/api/remote/devices/:deviceId/thumbnail', (req, res) => {
|
|
7102
7180
|
res.setHeader('Cache-Control', 'no-store');
|
|
7103
|
-
|
|
7181
|
+
if (wantsRemoteFrameBinaryRequest(req)) {
|
|
7182
|
+
sendRemoteFrameBinary(req, res, 'thumbnail');
|
|
7183
|
+
return;
|
|
7184
|
+
}
|
|
7185
|
+
|
|
7186
|
+
const thumbnail = remoteHub.getDeviceThumbnail(req.params.deviceId, {
|
|
7187
|
+
includeDataUrl: includeRemoteFrameDataUrl(req)
|
|
7188
|
+
});
|
|
7104
7189
|
if (!thumbnail) {
|
|
7105
7190
|
res.status(404).json({ ok: false, error: 'thumbnail-not-available' });
|
|
7106
7191
|
return;
|
|
@@ -7120,7 +7205,14 @@ app.post('/api/remote/devices/:deviceId/thumbnail/request', (req, res) => {
|
|
|
7120
7205
|
|
|
7121
7206
|
app.get('/api/remote/devices/:deviceId/live/frame', (req, res) => {
|
|
7122
7207
|
res.setHeader('Cache-Control', 'no-store');
|
|
7123
|
-
|
|
7208
|
+
if (wantsRemoteFrameBinaryRequest(req)) {
|
|
7209
|
+
sendRemoteFrameBinary(req, res, 'live');
|
|
7210
|
+
return;
|
|
7211
|
+
}
|
|
7212
|
+
|
|
7213
|
+
const frame = remoteHub.getDeviceLiveFrame(req.params.deviceId, {
|
|
7214
|
+
includeDataUrl: includeRemoteFrameDataUrl(req)
|
|
7215
|
+
});
|
|
7124
7216
|
if (!frame) {
|
|
7125
7217
|
res.status(404).json({ ok: false, error: 'live-frame-not-available' });
|
|
7126
7218
|
return;
|
|
@@ -12957,13 +12957,30 @@
|
|
|
12957
12957
|
}
|
|
12958
12958
|
|
|
12959
12959
|
function hasRemoteFleetThumbnail(device) {
|
|
12960
|
-
|
|
12961
|
-
return /^data:image\/(png|jpe?g|webp|svg\+xml);base64,/i.test(dataUrl);
|
|
12960
|
+
return isRemoteFleetFrameSource(getRemoteFleetFrameSource(device, 'thumbnail'));
|
|
12962
12961
|
}
|
|
12963
12962
|
|
|
12964
12963
|
function hasRemoteFleetLiveFrame(device) {
|
|
12965
|
-
|
|
12966
|
-
|
|
12964
|
+
return isRemoteFleetFrameSource(getRemoteFleetFrameSource(device, 'live'));
|
|
12965
|
+
}
|
|
12966
|
+
|
|
12967
|
+
function isRemoteFleetFrameSource(value) {
|
|
12968
|
+
const source = String(value || '').trim();
|
|
12969
|
+
return /^data:image\/(png|jpe?g|webp|svg\+xml);base64,/i.test(source)
|
|
12970
|
+
|| /^https?:\/\/(?:127(?:\.\d{1,3}){3}|localhost|\[::1\])(?::\d+)?\/api\/remote\//i.test(source)
|
|
12971
|
+
|| /^\/api\/remote\//i.test(source);
|
|
12972
|
+
}
|
|
12973
|
+
|
|
12974
|
+
function getRemoteFleetFrameSource(device, frameKind) {
|
|
12975
|
+
if (frameKind === 'live') {
|
|
12976
|
+
return String(
|
|
12977
|
+
getRemoteFleetDeviceField(device, 'liveFrameUrl', 'LiveFrameUrl', '')
|
|
12978
|
+
|| getRemoteFleetDeviceField(device, 'liveFrameDataUrl', 'LiveFrameDataUrl', ''));
|
|
12979
|
+
}
|
|
12980
|
+
|
|
12981
|
+
return String(
|
|
12982
|
+
getRemoteFleetDeviceField(device, 'thumbnailFrameUrl', 'ThumbnailFrameUrl', '')
|
|
12983
|
+
|| getRemoteFleetDeviceField(device, 'thumbnailDataUrl', 'ThumbnailDataUrl', ''));
|
|
12967
12984
|
}
|
|
12968
12985
|
|
|
12969
12986
|
function isRemoteFleetLiveActive(device) {
|
|
@@ -13245,9 +13262,9 @@
|
|
|
13245
13262
|
const liveStreamId = String(getRemoteFleetDeviceField(device, 'liveStreamId', 'LiveStreamId', ''));
|
|
13246
13263
|
const hasLiveFrame = hasRemoteFleetLiveFrame(device);
|
|
13247
13264
|
const hasThumbnail = hasRemoteFleetThumbnail(device);
|
|
13248
|
-
const
|
|
13249
|
-
?
|
|
13250
|
-
:
|
|
13265
|
+
const previewSource = hasLiveFrame
|
|
13266
|
+
? getRemoteFleetFrameSource(device, 'live')
|
|
13267
|
+
: getRemoteFleetFrameSource(device, 'thumbnail');
|
|
13251
13268
|
const previewAt = hasLiveFrame
|
|
13252
13269
|
? String(getRemoteFleetDeviceField(device, 'liveFrameReceivedAt', 'LiveFrameReceivedAt', ''))
|
|
13253
13270
|
: String(getRemoteFleetDeviceField(device, 'thumbnailReceivedAt', 'ThumbnailReceivedAt',
|
|
@@ -13309,7 +13326,7 @@
|
|
|
13309
13326
|
`;
|
|
13310
13327
|
if (hasLiveFrame || hasThumbnail) {
|
|
13311
13328
|
const image = document.createElement('img');
|
|
13312
|
-
image.src =
|
|
13329
|
+
image.src = previewSource;
|
|
13313
13330
|
image.alt = `${name} screen`;
|
|
13314
13331
|
image.loading = 'lazy';
|
|
13315
13332
|
image.decoding = 'async';
|
|
@@ -14104,7 +14121,7 @@
|
|
|
14104
14121
|
const focusedId = getRemoteFleetDeviceId(focusedDevice);
|
|
14105
14122
|
const focusedName = getRemoteFleetDeviceName(focusedDevice);
|
|
14106
14123
|
const liveActive = isRemoteFleetLiveActive(focusedDevice);
|
|
14107
|
-
const
|
|
14124
|
+
const liveFrameSource = getRemoteFleetFrameSource(focusedDevice, 'live');
|
|
14108
14125
|
const liveFrameAt = String(getRemoteFleetDeviceField(focusedDevice, 'liveFrameReceivedAt', 'LiveFrameReceivedAt', ''));
|
|
14109
14126
|
const liveStreamId = String(getRemoteFleetDeviceField(focusedDevice, 'liveStreamId', 'LiveStreamId', ''));
|
|
14110
14127
|
const hasLiveFrame = hasRemoteFleetLiveFrame(focusedDevice);
|
|
@@ -14135,7 +14152,7 @@
|
|
|
14135
14152
|
`;
|
|
14136
14153
|
if (hasLiveFrame) {
|
|
14137
14154
|
const image = document.createElement('img');
|
|
14138
|
-
image.src =
|
|
14155
|
+
image.src = liveFrameSource;
|
|
14139
14156
|
image.alt = `${focusedName} live screen`;
|
|
14140
14157
|
image.decoding = 'async';
|
|
14141
14158
|
image.style.cssText = `
|
|
@@ -14238,13 +14255,13 @@
|
|
|
14238
14255
|
const createDevicePreview = (device, mode = 'tile') => {
|
|
14239
14256
|
const name = getRemoteFleetDeviceName(device);
|
|
14240
14257
|
const connectedDevice = isRemoteFleetDeviceConnected(device);
|
|
14241
|
-
const thumbnailDataUrl = String(device?.thumbnailDataUrl || device?.ThumbnailDataUrl || '');
|
|
14242
14258
|
const thumbnailCapturedAt = String(device?.thumbnailCapturedAt || device?.ThumbnailCapturedAt || '');
|
|
14243
|
-
const liveFrameDataUrl = String(device?.liveFrameDataUrl || device?.LiveFrameDataUrl || '');
|
|
14244
14259
|
const liveFrameReceivedAt = String(device?.liveFrameReceivedAt || device?.LiveFrameReceivedAt || '');
|
|
14245
14260
|
const hasThumbnail = hasRemoteFleetThumbnail(device);
|
|
14246
14261
|
const hasLiveFrame = hasRemoteFleetLiveFrame(device);
|
|
14247
|
-
const
|
|
14262
|
+
const previewSource = hasLiveFrame
|
|
14263
|
+
? getRemoteFleetFrameSource(device, 'live')
|
|
14264
|
+
: getRemoteFleetFrameSource(device, 'thumbnail');
|
|
14248
14265
|
const previewAt = hasLiveFrame ? liveFrameReceivedAt : thumbnailCapturedAt;
|
|
14249
14266
|
const isDetail = mode === 'detail';
|
|
14250
14267
|
|
|
@@ -14262,7 +14279,7 @@
|
|
|
14262
14279
|
|
|
14263
14280
|
if (hasLiveFrame || hasThumbnail) {
|
|
14264
14281
|
const image = document.createElement('img');
|
|
14265
|
-
image.src =
|
|
14282
|
+
image.src = previewSource;
|
|
14266
14283
|
image.alt = hasLiveFrame ? `${name} live frame` : `${name} thumbnail`;
|
|
14267
14284
|
image.loading = 'lazy';
|
|
14268
14285
|
image.decoding = 'async';
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mainAssemblyName": "MindExecution.Web",
|
|
3
3
|
"resources": {
|
|
4
|
-
"hash": "sha256-
|
|
4
|
+
"hash": "sha256-85uTc0gcvy3kY8SBQJxkQmIrLfblhTpX8tZWjJP3QnE=",
|
|
5
5
|
"fingerprinting": {
|
|
6
6
|
"Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
|
|
7
7
|
"Markdig.d1j7v41cl1.dll": "Markdig.dll",
|
|
@@ -123,16 +123,16 @@
|
|
|
123
123
|
"System.brmz7yk5qh.dll": "System.dll",
|
|
124
124
|
"netstandard.yvr3prsx0x.dll": "netstandard.dll",
|
|
125
125
|
"System.Private.CoreLib.ns29bor93l.dll": "System.Private.CoreLib.dll",
|
|
126
|
-
"MindExecution.Core.
|
|
127
|
-
"MindExecution.Kernel.
|
|
128
|
-
"MindExecution.Plugins.Admin.
|
|
129
|
-
"MindExecution.Plugins.Business.
|
|
130
|
-
"MindExecution.Plugins.Concept.
|
|
131
|
-
"MindExecution.Plugins.Directory.
|
|
132
|
-
"MindExecution.Plugins.PlanMaster.
|
|
133
|
-
"MindExecution.Plugins.YouTube.
|
|
134
|
-
"MindExecution.Shared.
|
|
135
|
-
"MindExecution.Web.
|
|
126
|
+
"MindExecution.Core.xg9yy9l5dz.dll": "MindExecution.Core.dll",
|
|
127
|
+
"MindExecution.Kernel.erg96341xf.dll": "MindExecution.Kernel.dll",
|
|
128
|
+
"MindExecution.Plugins.Admin.11j9vpdm9u.dll": "MindExecution.Plugins.Admin.dll",
|
|
129
|
+
"MindExecution.Plugins.Business.oyskf08knn.dll": "MindExecution.Plugins.Business.dll",
|
|
130
|
+
"MindExecution.Plugins.Concept.keia4ox68c.dll": "MindExecution.Plugins.Concept.dll",
|
|
131
|
+
"MindExecution.Plugins.Directory.7pus9p63ym.dll": "MindExecution.Plugins.Directory.dll",
|
|
132
|
+
"MindExecution.Plugins.PlanMaster.wr3pupzfyo.dll": "MindExecution.Plugins.PlanMaster.dll",
|
|
133
|
+
"MindExecution.Plugins.YouTube.kpfew1eggc.dll": "MindExecution.Plugins.YouTube.dll",
|
|
134
|
+
"MindExecution.Shared.kzibxbai3y.dll": "MindExecution.Shared.dll",
|
|
135
|
+
"MindExecution.Web.6fjnkr9ty4.dll": "MindExecution.Web.dll",
|
|
136
136
|
"dotnet.js": "dotnet.js",
|
|
137
137
|
"dotnet.native.qc8g39g30v.js": "dotnet.native.js",
|
|
138
138
|
"dotnet.native.boem75ye5i.wasm": "dotnet.native.wasm",
|
|
@@ -278,18 +278,18 @@
|
|
|
278
278
|
"System.Xml.XDocument.sn51jas17n.dll": "sha256-GNI2kFgFmPTwzuzwUn8gxK+AzGLUWRJFdg9JzIbrybQ=",
|
|
279
279
|
"System.brmz7yk5qh.dll": "sha256-CfM2miyj1KHApFmqMdLYWio3S/jrdON2pW9Xr2nTwlo=",
|
|
280
280
|
"netstandard.yvr3prsx0x.dll": "sha256-EksNn8Luo4bOWqJ6X7dIe9qG9oOqwOVzjH2xYyMNi+E=",
|
|
281
|
-
"MindExecution.Core.
|
|
282
|
-
"MindExecution.Kernel.
|
|
283
|
-
"MindExecution.Plugins.Concept.
|
|
284
|
-
"MindExecution.Plugins.PlanMaster.
|
|
285
|
-
"MindExecution.Shared.
|
|
286
|
-
"MindExecution.Web.
|
|
281
|
+
"MindExecution.Core.xg9yy9l5dz.dll": "sha256-cRrcPtFn2SUkdgWA68l7+CQbGso1QWczG5az1KYpLUU=",
|
|
282
|
+
"MindExecution.Kernel.erg96341xf.dll": "sha256-5hDopeSFSFHb5tDeLFj0jrSt6XRq4SYxB8nyFJ6H9RQ=",
|
|
283
|
+
"MindExecution.Plugins.Concept.keia4ox68c.dll": "sha256-rO8bWy0n6NZKqMzFpcIjy/p1kG8mPSuTUZ+UMTWugf8=",
|
|
284
|
+
"MindExecution.Plugins.PlanMaster.wr3pupzfyo.dll": "sha256-pE7MM4cMUkHzg5wTQtq8Vgk+RSjlQtO44T9AwQsYDqw=",
|
|
285
|
+
"MindExecution.Shared.kzibxbai3y.dll": "sha256-4CE9pNlfu9pIL+wwsbaU4ARQLcYelkl2sqkwAJD9sD4=",
|
|
286
|
+
"MindExecution.Web.6fjnkr9ty4.dll": "sha256-7o2Y3AvthOWiFF9+lHnqahGmcN/0tDuBtJhxGdcMN44="
|
|
287
287
|
},
|
|
288
288
|
"lazyAssembly": {
|
|
289
|
-
"MindExecution.Plugins.Admin.
|
|
290
|
-
"MindExecution.Plugins.Business.
|
|
291
|
-
"MindExecution.Plugins.Directory.
|
|
292
|
-
"MindExecution.Plugins.YouTube.
|
|
289
|
+
"MindExecution.Plugins.Admin.11j9vpdm9u.dll": "sha256-lZvp68Zm2iFwt93gRGlHDKVnywJT2hHxA3JHu4Z3PfA=",
|
|
290
|
+
"MindExecution.Plugins.Business.oyskf08knn.dll": "sha256-oL53lWZ8Lp8lZuqc3UP+qIGSEVKJvVvfov+2xyQ3INg=",
|
|
291
|
+
"MindExecution.Plugins.Directory.7pus9p63ym.dll": "sha256-a1eUvklwiLwuCPBk05omRoirn1tRqVgjogVW8/UAAuc=",
|
|
292
|
+
"MindExecution.Plugins.YouTube.kpfew1eggc.dll": "sha256-COvvpOYO8nsEePBr3CCF4Wv0CWfvvOAoXn54tmikwwc="
|
|
293
293
|
}
|
|
294
294
|
},
|
|
295
295
|
"cacheBootResources": true,
|
package/wwwroot/index.html
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<title>MindExec | Run your ideas as AI task graphs</title>
|
|
8
8
|
<meta name="description" content="MindExec is an AI execution canvas for solo builders, researchers, developers, and creators. Start with free browser tools, then move serious work into saved MindCanvas projects." />
|
|
9
9
|
<base href="/" />
|
|
10
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260613-
|
|
11
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260613-
|
|
10
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260613-remote-binary-frame-v509" />
|
|
11
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260613-remote-binary-frame-v509" />
|
|
12
12
|
<!-- ?쇄뼹??Font Awesome (local) ?쇄뼹??-->
|
|
13
13
|
<link rel="stylesheet" href="_content/MindExecution.Shared/lib/font-awesome/css/all.min.css" />
|
|
14
14
|
<!-- ?꿎뼯??-->
|
|
@@ -558,7 +558,7 @@
|
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
const base = '_content/MindExecution.Shared/js/';
|
|
561
|
-
const scriptVersion = '20260613-remote-
|
|
561
|
+
const scriptVersion = '20260613-remote-binary-frame-v509';
|
|
562
562
|
const scriptUrl = (script) => `${base}${script}?v=${scriptVersion}`;
|
|
563
563
|
console.log(`[Script Loader] Shared JS version: ${scriptVersion}`);
|
|
564
564
|
const criticalScripts = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
self.assetsManifest = {
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "HB1IB45K",
|
|
3
3
|
"assets": [
|
|
4
4
|
{
|
|
5
5
|
"hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"url": "_content/MindExecution.Shared/js/mind-map-core.js.backup"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
"hash": "sha256-
|
|
89
|
+
"hash": "sha256-2LFL3oGey+usyB7lpywzpKYMhBmlMhrXi9IZdtdUJZU=",
|
|
90
90
|
"url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
@@ -410,44 +410,44 @@
|
|
|
410
410
|
"url": "_framework/MimeMapping.og9ys58ylm.dll"
|
|
411
411
|
},
|
|
412
412
|
{
|
|
413
|
-
"hash": "sha256-
|
|
414
|
-
"url": "_framework/MindExecution.Core.
|
|
413
|
+
"hash": "sha256-cRrcPtFn2SUkdgWA68l7+CQbGso1QWczG5az1KYpLUU=",
|
|
414
|
+
"url": "_framework/MindExecution.Core.xg9yy9l5dz.dll"
|
|
415
415
|
},
|
|
416
416
|
{
|
|
417
|
-
"hash": "sha256-
|
|
418
|
-
"url": "_framework/MindExecution.Kernel.
|
|
417
|
+
"hash": "sha256-5hDopeSFSFHb5tDeLFj0jrSt6XRq4SYxB8nyFJ6H9RQ=",
|
|
418
|
+
"url": "_framework/MindExecution.Kernel.erg96341xf.dll"
|
|
419
419
|
},
|
|
420
420
|
{
|
|
421
|
-
"hash": "sha256-
|
|
422
|
-
"url": "_framework/MindExecution.Plugins.Admin.
|
|
421
|
+
"hash": "sha256-lZvp68Zm2iFwt93gRGlHDKVnywJT2hHxA3JHu4Z3PfA=",
|
|
422
|
+
"url": "_framework/MindExecution.Plugins.Admin.11j9vpdm9u.dll"
|
|
423
423
|
},
|
|
424
424
|
{
|
|
425
|
-
"hash": "sha256-
|
|
426
|
-
"url": "_framework/MindExecution.Plugins.Business.
|
|
425
|
+
"hash": "sha256-oL53lWZ8Lp8lZuqc3UP+qIGSEVKJvVvfov+2xyQ3INg=",
|
|
426
|
+
"url": "_framework/MindExecution.Plugins.Business.oyskf08knn.dll"
|
|
427
427
|
},
|
|
428
428
|
{
|
|
429
|
-
"hash": "sha256-
|
|
430
|
-
"url": "_framework/MindExecution.Plugins.Concept.
|
|
429
|
+
"hash": "sha256-rO8bWy0n6NZKqMzFpcIjy/p1kG8mPSuTUZ+UMTWugf8=",
|
|
430
|
+
"url": "_framework/MindExecution.Plugins.Concept.keia4ox68c.dll"
|
|
431
431
|
},
|
|
432
432
|
{
|
|
433
|
-
"hash": "sha256-
|
|
434
|
-
"url": "_framework/MindExecution.Plugins.Directory.
|
|
433
|
+
"hash": "sha256-a1eUvklwiLwuCPBk05omRoirn1tRqVgjogVW8/UAAuc=",
|
|
434
|
+
"url": "_framework/MindExecution.Plugins.Directory.7pus9p63ym.dll"
|
|
435
435
|
},
|
|
436
436
|
{
|
|
437
|
-
"hash": "sha256-
|
|
438
|
-
"url": "_framework/MindExecution.Plugins.PlanMaster.
|
|
437
|
+
"hash": "sha256-pE7MM4cMUkHzg5wTQtq8Vgk+RSjlQtO44T9AwQsYDqw=",
|
|
438
|
+
"url": "_framework/MindExecution.Plugins.PlanMaster.wr3pupzfyo.dll"
|
|
439
439
|
},
|
|
440
440
|
{
|
|
441
|
-
"hash": "sha256-
|
|
442
|
-
"url": "_framework/MindExecution.Plugins.YouTube.
|
|
441
|
+
"hash": "sha256-COvvpOYO8nsEePBr3CCF4Wv0CWfvvOAoXn54tmikwwc=",
|
|
442
|
+
"url": "_framework/MindExecution.Plugins.YouTube.kpfew1eggc.dll"
|
|
443
443
|
},
|
|
444
444
|
{
|
|
445
|
-
"hash": "sha256-
|
|
446
|
-
"url": "_framework/MindExecution.Shared.
|
|
445
|
+
"hash": "sha256-4CE9pNlfu9pIL+wwsbaU4ARQLcYelkl2sqkwAJD9sD4=",
|
|
446
|
+
"url": "_framework/MindExecution.Shared.kzibxbai3y.dll"
|
|
447
447
|
},
|
|
448
448
|
{
|
|
449
|
-
"hash": "sha256-
|
|
450
|
-
"url": "_framework/MindExecution.Web.
|
|
449
|
+
"hash": "sha256-7o2Y3AvthOWiFF9+lHnqahGmcN/0tDuBtJhxGdcMN44=",
|
|
450
|
+
"url": "_framework/MindExecution.Web.6fjnkr9ty4.dll"
|
|
451
451
|
},
|
|
452
452
|
{
|
|
453
453
|
"hash": "sha256-IsZJ91/OW+fHzNqIgEc7Y072ns8z9dGritiSyvR9Wgc=",
|
|
@@ -770,7 +770,7 @@
|
|
|
770
770
|
"url": "_framework/Websocket.Client.vapounvmnl.dll"
|
|
771
771
|
},
|
|
772
772
|
{
|
|
773
|
-
"hash": "sha256-
|
|
773
|
+
"hash": "sha256-ZSebVg6+73YAEhmuXnGeKZGeTBILK2WJbFuyP6Ydv2Q=",
|
|
774
774
|
"url": "_framework/blazor.boot.json"
|
|
775
775
|
},
|
|
776
776
|
{
|
|
@@ -834,7 +834,7 @@
|
|
|
834
834
|
"url": "image-manifest.json"
|
|
835
835
|
},
|
|
836
836
|
{
|
|
837
|
-
"hash": "sha256-
|
|
837
|
+
"hash": "sha256-4r5HCCe1b4vT4Pzfg8qixJLEq3JWH57lt3fVWc0zLPM=",
|
|
838
838
|
"url": "index.html"
|
|
839
839
|
},
|
|
840
840
|
{
|
|
Binary file
|
|
Binary file
|