buckyos 0.7.138 → 0.7.142
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/cli/core/app.ts +4 -0
- package/cli/core/auth.ts +2 -3
- package/cli/dist/cli.mjs +547 -127
- package/cli/dist/cli.mjs.map +1 -1
- package/cli/modules/aiws.ts +294 -0
- package/cli/modules/executor.ts +98 -0
- package/cli/version.ts +1 -1
- package/dist/account.d.ts +0 -2
- package/dist/account.d.ts.map +1 -1
- package/dist/aiworkspace_client.d.ts +91 -0
- package/dist/aiworkspace_client.d.ts.map +1 -0
- package/dist/app-frame.cjs +1 -1
- package/dist/app-frame.cjs.map +1 -1
- package/dist/app-frame.d.ts +103 -3
- package/dist/app-frame.d.ts.map +1 -1
- package/dist/app-frame.mjs +189 -8
- package/dist/app-frame.mjs.map +1 -1
- package/dist/browser.cjs +1 -1
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +2 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.mjs +18 -15
- package/dist/browser.mjs.map +1 -1
- package/dist/content.cjs +1 -1
- package/dist/content.cjs.map +1 -1
- package/dist/content.d.ts +18 -0
- package/dist/content.d.ts.map +1 -1
- package/dist/content.mjs +61 -1
- package/dist/content.mjs.map +1 -1
- package/dist/executor_client-b3ff97ba.js +13 -0
- package/dist/executor_client-b3ff97ba.js.map +1 -0
- package/dist/{ndm_proxy-6b03b9ec.mjs → executor_client-eb372968.mjs} +901 -396
- package/dist/executor_client-eb372968.mjs.map +1 -0
- package/dist/executor_client.d.ts +138 -0
- package/dist/executor_client.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +23 -15
- package/dist/index.mjs.map +1 -1
- package/dist/internal/hash_worker.d.ts +2 -1
- package/dist/internal/hash_worker.d.ts.map +1 -1
- package/dist/internal/tus_client.d.ts +3 -0
- package/dist/internal/tus_client.d.ts.map +1 -1
- package/dist/namelib.d.ts +1 -10
- package/dist/namelib.d.ts.map +1 -1
- package/dist/ndm_client.d.ts +56 -7
- package/dist/ndm_client.d.ts.map +1 -1
- package/dist/ndn_types-08dc9ef1.js +2 -0
- package/dist/ndn_types-08dc9ef1.js.map +1 -0
- package/dist/{ndn_types-ac9c1e48.mjs → ndn_types-bbb1f6a6.mjs} +53 -100
- package/dist/ndn_types-bbb1f6a6.mjs.map +1 -0
- package/dist/nfsp.cjs +1 -1
- package/dist/nfsp.cjs.map +1 -1
- package/dist/nfsp.d.ts +16 -0
- package/dist/nfsp.d.ts.map +1 -1
- package/dist/nfsp.mjs +6 -0
- package/dist/nfsp.mjs.map +1 -1
- package/dist/node.cjs +1 -1
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +2 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.mjs +18 -15
- package/dist/node.mjs.map +1 -1
- package/dist/provision.cjs +2 -2
- package/dist/provision.cjs.map +1 -1
- package/dist/provision.mjs +18 -12
- package/dist/provision.mjs.map +1 -1
- package/dist/provision_activate.d.ts.map +1 -1
- package/dist/runtime.d.ts +3 -4
- package/dist/runtime.d.ts.map +1 -1
- package/dist/sdk_core.d.ts +4 -0
- package/dist/sdk_core.d.ts.map +1 -1
- package/dist/{tus_client-2b915a81.js → tus_client-65c5fc5e.js} +4 -4
- package/dist/tus_client-65c5fc5e.js.map +1 -0
- package/dist/{tus_client-19baa342.mjs → tus_client-d313689e.mjs} +40 -2
- package/dist/tus_client-d313689e.mjs.map +1 -0
- package/dist/types.d.ts +0 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/verify-hub-client.d.ts +1 -9
- package/dist/verify-hub-client.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/ndm_proxy-67651066.js +0 -13
- package/dist/ndm_proxy-67651066.js.map +0 -1
- package/dist/ndm_proxy-6b03b9ec.mjs.map +0 -1
- package/dist/ndn_types-324121ae.js +0 -2
- package/dist/ndn_types-324121ae.js.map +0 -1
- package/dist/ndn_types-ac9c1e48.mjs.map +0 -1
- package/dist/tus_client-19baa342.mjs.map +0 -1
- package/dist/tus_client-2b915a81.js.map +0 -1
|
@@ -35,7 +35,7 @@ var __privateMethod = (obj, member, method) => {
|
|
|
35
35
|
return method;
|
|
36
36
|
};
|
|
37
37
|
var _listener, _listeners, _cancelled, _allowInsecure, _gzip, _headers, _method, _timeout, _url, _body, _bodyType, _creds, _preflight, _process, _retry, _signal, _throttle, _getUrlFunc, _send, send_fn, _statusCode, _statusMessage, _headers2, _body2, _request, _error, _names, _data, _dataLength, _writeData, writeData_fn, _data2, _offset, _bytesRead, _parent, _maxInflation, _incrementBytesRead, incrementBytesRead_fn, _peekBytes, peekBytes_fn, _r, _s, _v, _networkV, _privateKey, _options, _type, _to, _data3, _nonce, _gasLimit, _gasPrice, _maxPriorityFeePerGas, _maxFeePerGas, _value, _chainId, _sig, _accessList, _maxFeePerBlobGas, _blobVersionedHashes, _kzg, _blobs, _auths, _blobWrapperVersion, _getSerialized, getSerialized_fn, _types, _fullTypes, _encoderCache, _getEncoder, getEncoder_fn, _offset2, _tokens, _subTokenString, subTokenString_fn, _walkAsync, walkAsync_fn, _getCoder, getCoder_fn, _errors, _events, _functions, _abiCoder, _getFunction, getFunction_fn, _getEvent, getEvent_fn, _transactions, _logs, _startBlock, _iface, _iface2, _filter, _a, _supports2544, _resolver, _fetch, fetch_fn, _getResolver, getResolver_fn, _url2, _processFunc, _name, _chainId2, _plugins, _provider, _poller, _interval, _blockNumber, _poll, poll_fn, _provider2, _poll2, _running, _tag, _lastBlock, _filter2, _hash, _provider3, _filter3, _poller2, _running2, _blockNumber2, _poll3, poll_fn2, _subs, _plugins2, _pausedState, _destroyed, _networkPromise, _anyNetwork, _performCache, _lastBlockNumber, _nextTimer, _timers, _disableCcipRead, _requestRate, _requestTimes, _options2, _getDelay, getDelay_fn, _perform, perform_fn, _call, call_fn, _checkNetwork, checkNetwork_fn, _getAccountValue, getAccountValue_fn, _getBlock, getBlock_fn, _hasSub, hasSub_fn, _getSub, getSub_fn, _throwUnsupported, throwUnsupported_fn, _provider4, _filterIdPromise, _poller3, _running3, _network, _hault, _poll4, poll_fn3, _teardown, teardown_fn, _event, _options3, _nextId, _payloads, _drainTimer, _notReady, _network2, _pendingDetectNetwork, _scheduleDrain, scheduleDrain_fn, _pollingInterval, _connect, _signingKey, _data4, _checksum, _words, _loadWords, loadWords_fn, _account, account_fn, _fromSeed, fromSeed_fn, _fromAccount, fromAccount_fn;
|
|
38
|
-
import {
|
|
38
|
+
import { u as DID, v as getBrowserIdentityRaw, w as clearBrowserUserInfo, x as saveBrowserIdentity, y as saveBrowserUserInfo, z as getBrowserUserInfo, A as clearBrowserIdentity, N as NODE_IDENTITY_SCHEMA_V2, f as isBuckyOSLocalNodeIdentityConfig, o as parseBuckyOSOwnerDocument, h as hashPassword, B as saveLocalAccountInfo, C as cleanLocalAccountInfo, E as canonicalize, F as signJwtEdDSA, G as ChunkId, H as sha256Bytes, I as FileObject, O as ObjId, J as DirObject, S as SimpleChunkList } from "./ndn_types-bbb1f6a6.mjs";
|
|
39
39
|
class RPCError extends Error {
|
|
40
40
|
constructor(message, code, data) {
|
|
41
41
|
super(message);
|
|
@@ -323,6 +323,91 @@ function buildJumpUrl(action, params, jumpBase = DEFAULT_JUMP_BASE_URL) {
|
|
|
323
323
|
const fragment = new URLSearchParams(params).toString();
|
|
324
324
|
return `${base.origin}${path}${fragment ? `#${fragment}` : ""}`;
|
|
325
325
|
}
|
|
326
|
+
const AIWORKSPACE_SERVICE_NAME = "aiworkspace";
|
|
327
|
+
class AiwsFailure extends Error {
|
|
328
|
+
constructor(error) {
|
|
329
|
+
super(`${error.code}${error.sub_code ? `/${error.sub_code}` : ""}: ${error.detail}`);
|
|
330
|
+
this.name = "AiwsFailure";
|
|
331
|
+
this.code = error.code;
|
|
332
|
+
this.subCode = error.sub_code;
|
|
333
|
+
this.data = error.data;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
class AiWorkspaceClient {
|
|
337
|
+
constructor(rpcClient) {
|
|
338
|
+
this.rpcClient = rpcClient;
|
|
339
|
+
}
|
|
340
|
+
async call(method, params) {
|
|
341
|
+
const raw = await this.rpcClient.call(method, params);
|
|
342
|
+
if (raw && typeof raw === "object" && raw.ok === false)
|
|
343
|
+
throw new AiwsFailure(raw.error);
|
|
344
|
+
return raw;
|
|
345
|
+
}
|
|
346
|
+
// ---- workspace
|
|
347
|
+
list() {
|
|
348
|
+
return this.call("ws.list", {});
|
|
349
|
+
}
|
|
350
|
+
info(workspace_id) {
|
|
351
|
+
return this.call("ws.get_info", { workspace_id });
|
|
352
|
+
}
|
|
353
|
+
getUserState(workspace_id) {
|
|
354
|
+
return this.call("ws.get_user_state", { workspace_id });
|
|
355
|
+
}
|
|
356
|
+
setUserState(workspace_id, entries, expect) {
|
|
357
|
+
return this.call("ws.set_user_state", { workspace_id, entries, ...expect ? { expect } : {} });
|
|
358
|
+
}
|
|
359
|
+
// ---- document
|
|
360
|
+
resolve(workspace_id, reference) {
|
|
361
|
+
return this.call("doc.resolve", { workspace_id, reference });
|
|
362
|
+
}
|
|
363
|
+
resolvePath(workspace_id, path) {
|
|
364
|
+
return this.call("doc.resolve", { workspace_id, path });
|
|
365
|
+
}
|
|
366
|
+
read(workspace_id, entity_id, selector) {
|
|
367
|
+
return this.call("doc.read", { workspace_id, entity_id, ...selector ? { selector } : {} });
|
|
368
|
+
}
|
|
369
|
+
query(workspace_id, params) {
|
|
370
|
+
return this.call("doc.query", { workspace_id, ...params });
|
|
371
|
+
}
|
|
372
|
+
outline(workspace_id) {
|
|
373
|
+
return this.call("doc.outline", { workspace_id });
|
|
374
|
+
}
|
|
375
|
+
prepare(workspace_id, request) {
|
|
376
|
+
return this.rpcClient.call("doc.prepare", { workspace_id, ...request });
|
|
377
|
+
}
|
|
378
|
+
/** The three-state commit result (`status: accepted | conflict | rejected`), never thrown. */
|
|
379
|
+
commit(workspace_id, request) {
|
|
380
|
+
return this.rpcClient.call("doc.commit", { workspace_id, ...request });
|
|
381
|
+
}
|
|
382
|
+
getSubmission(workspace_id, epoch, idempotency_key) {
|
|
383
|
+
return this.call("doc.get_submission", { workspace_id, epoch, idempotency_key });
|
|
384
|
+
}
|
|
385
|
+
// ---- runs (M3 executor protocol)
|
|
386
|
+
runStart(workspace_id, program, params, idempotency_key) {
|
|
387
|
+
return this.call("proc.start", { workspace_id, program, params, idempotency_key });
|
|
388
|
+
}
|
|
389
|
+
runGet(workspace_id, run_id, choices) {
|
|
390
|
+
return this.call("proc.get", { workspace_id, run_id, ...choices ? { choices } : {} });
|
|
391
|
+
}
|
|
392
|
+
runList(workspace_id, wish_id, limit) {
|
|
393
|
+
return this.call("proc.list", { workspace_id, ...wish_id ? { wish_id } : {}, ...limit ? { limit } : {} });
|
|
394
|
+
}
|
|
395
|
+
runClaim(workspace_id, run_id, claim_token, executor) {
|
|
396
|
+
return this.call("proc.claim", { workspace_id, run_id, claim_token, ...executor ? { executor } : {} });
|
|
397
|
+
}
|
|
398
|
+
runHeartbeat(workspace_id, run_id, attempt, progress) {
|
|
399
|
+
return this.call("proc.heartbeat", { workspace_id, run_id, attempt, ...progress ? { progress } : {} });
|
|
400
|
+
}
|
|
401
|
+
runReport(workspace_id, report) {
|
|
402
|
+
return this.call("proc.report", { workspace_id, ...report });
|
|
403
|
+
}
|
|
404
|
+
runApply(workspace_id, run_id, plan_digest, session_id) {
|
|
405
|
+
return this.call("proc.apply", { workspace_id, run_id, plan_digest, ...session_id ? { session_id } : {} });
|
|
406
|
+
}
|
|
407
|
+
runCancel(workspace_id, run_id) {
|
|
408
|
+
return this.call("proc.cancel", { workspace_id, run_id });
|
|
409
|
+
}
|
|
410
|
+
}
|
|
326
411
|
function serializeAuthTarget(target) {
|
|
327
412
|
if (!target || typeof target !== "object") {
|
|
328
413
|
throw new RPCError("verify-hub auth target is required");
|
|
@@ -412,21 +497,6 @@ class VerifyHubClient {
|
|
|
412
497
|
}
|
|
413
498
|
return this.rpcClient.call("verify_token", payload);
|
|
414
499
|
}
|
|
415
|
-
static normalizeLoginResponse(response) {
|
|
416
|
-
if ("user_info" in response) {
|
|
417
|
-
return {
|
|
418
|
-
user_name: response.user_info.show_name,
|
|
419
|
-
user_id: response.user_info.user_id,
|
|
420
|
-
user_type: response.user_info.user_type,
|
|
421
|
-
session_token: response.session_token,
|
|
422
|
-
refresh_token: response.refresh_token
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
if (!response.session_token) {
|
|
426
|
-
throw new RPCError("login_by_password response missing session_token");
|
|
427
|
-
}
|
|
428
|
-
return response;
|
|
429
|
-
}
|
|
430
500
|
}
|
|
431
501
|
const TASK_MANAGER_SERVICE_UNIQUE_ID = "task-manager";
|
|
432
502
|
const TASK_MANAGER_SERVICE_NAME = "task-manager";
|
|
@@ -3453,6 +3523,9 @@ class BuckyOSRuntime {
|
|
|
3453
3523
|
getAiccClient() {
|
|
3454
3524
|
return new AiccClient(this.getServiceRpcClient("aicc"));
|
|
3455
3525
|
}
|
|
3526
|
+
getAiWorkspaceClient() {
|
|
3527
|
+
return new AiWorkspaceClient(this.getServiceRpcClient(AIWORKSPACE_SERVICE_NAME));
|
|
3528
|
+
}
|
|
3456
3529
|
getMsgQueueClient() {
|
|
3457
3530
|
return new MsgQueueClient(this.getServiceRpcClient("kmsg"));
|
|
3458
3531
|
}
|
|
@@ -3838,27 +3911,22 @@ class BuckyOSRuntime {
|
|
|
3838
3911
|
}, claims, material.keyPem);
|
|
3839
3912
|
}
|
|
3840
3913
|
async loadLocalSigningMaterial() {
|
|
3841
|
-
await importNodeModule$1("node:fs/promises");
|
|
3842
3914
|
const path = await importNodeModule$1("node:path");
|
|
3843
3915
|
const configuredUserId = this.getOwnerUserId();
|
|
3844
3916
|
if (!configuredUserId) {
|
|
3845
3917
|
const etcDir = await this.getBuckyOSEtcDir();
|
|
3846
|
-
const
|
|
3847
|
-
|
|
3848
|
-
|
|
3918
|
+
const nodeIdentityPath = path.join(etcDir, "node_identity.json");
|
|
3919
|
+
const metadata = await this.readNodeIdentityMetadata(nodeIdentityPath);
|
|
3920
|
+
if (!metadata) {
|
|
3921
|
+
throw new Error(`failed to load ${NODE_IDENTITY_SCHEMA_V2} node identity from ${nodeIdentityPath}`);
|
|
3849
3922
|
}
|
|
3850
|
-
const
|
|
3851
|
-
if (!
|
|
3852
|
-
throw new Error(`failed to load
|
|
3923
|
+
const material = await this.loadDeviceSigningMaterial(etcDir, metadata);
|
|
3924
|
+
if (!material) {
|
|
3925
|
+
throw new Error(`failed to load authentication private key of ${metadata.deviceDid}`);
|
|
3853
3926
|
}
|
|
3854
|
-
this.config.userid = deviceName;
|
|
3855
|
-
this.config.ownerUserId = deviceName;
|
|
3856
|
-
return
|
|
3857
|
-
keyPem,
|
|
3858
|
-
issuer: deviceName,
|
|
3859
|
-
subject: deviceName,
|
|
3860
|
-
sourcePath: path.join(etcDir, "node_private_key.pem")
|
|
3861
|
-
};
|
|
3927
|
+
this.config.userid = metadata.deviceName;
|
|
3928
|
+
this.config.ownerUserId = metadata.deviceName;
|
|
3929
|
+
return material;
|
|
3862
3930
|
}
|
|
3863
3931
|
const roots = await this.getPrivateKeySearchRoots();
|
|
3864
3932
|
const deviceMaterial = await this.tryLoadDeviceSigningMaterial(configuredUserId, roots);
|
|
@@ -3917,45 +3985,19 @@ class BuckyOSRuntime {
|
|
|
3917
3985
|
async readNodeIdentityMetadata(nodeIdentityPath) {
|
|
3918
3986
|
const fs = await importNodeModule$1("node:fs/promises");
|
|
3919
3987
|
try {
|
|
3920
|
-
const
|
|
3921
|
-
|
|
3922
|
-
|
|
3988
|
+
const parsed = JSON.parse(await fs.readFile(nodeIdentityPath, "utf8"));
|
|
3989
|
+
if (!isBuckyOSLocalNodeIdentityConfig(parsed)) {
|
|
3990
|
+
return null;
|
|
3991
|
+
}
|
|
3923
3992
|
return {
|
|
3924
|
-
deviceName,
|
|
3925
|
-
deviceDid:
|
|
3926
|
-
zoneDid:
|
|
3927
|
-
zoneName: typeof parsed.zone_name === "string" ? parsed.zone_name.trim() || null : null
|
|
3993
|
+
deviceName: parsed.device_name,
|
|
3994
|
+
deviceDid: parsed.device_did,
|
|
3995
|
+
zoneDid: parsed.zone_did
|
|
3928
3996
|
};
|
|
3929
3997
|
} catch {
|
|
3930
3998
|
return null;
|
|
3931
3999
|
}
|
|
3932
4000
|
}
|
|
3933
|
-
extractDeviceNameFromIdentityPayload(payload) {
|
|
3934
|
-
const directName = typeof payload.device_name === "string" ? payload.device_name.trim() : "";
|
|
3935
|
-
if (directName) {
|
|
3936
|
-
return directName;
|
|
3937
|
-
}
|
|
3938
|
-
const miniDocJwt = typeof payload.device_mini_doc_jwt === "string" ? payload.device_mini_doc_jwt : null;
|
|
3939
|
-
const miniDocClaims = parseSessionTokenClaims(miniDocJwt);
|
|
3940
|
-
const miniDocName = typeof (miniDocClaims == null ? void 0 : miniDocClaims.n) === "string" ? miniDocClaims.n.trim() : "";
|
|
3941
|
-
if (miniDocName) {
|
|
3942
|
-
return miniDocName;
|
|
3943
|
-
}
|
|
3944
|
-
const deviceDocJwt = typeof payload.device_doc_jwt === "string" ? payload.device_doc_jwt : null;
|
|
3945
|
-
const deviceDocClaims = parseSessionTokenClaims(deviceDocJwt);
|
|
3946
|
-
for (const claimKey of ["name", "sub"]) {
|
|
3947
|
-
const claimValue = deviceDocClaims == null ? void 0 : deviceDocClaims[claimKey];
|
|
3948
|
-
const candidate = typeof claimValue === "string" ? claimValue.trim() : "";
|
|
3949
|
-
if (candidate) {
|
|
3950
|
-
return candidate;
|
|
3951
|
-
}
|
|
3952
|
-
}
|
|
3953
|
-
return null;
|
|
3954
|
-
}
|
|
3955
|
-
async readDeviceNameFromNodeIdentityPath(nodeIdentityPath) {
|
|
3956
|
-
const metadata = await this.readNodeIdentityMetadata(nodeIdentityPath);
|
|
3957
|
-
return (metadata == null ? void 0 : metadata.deviceName) ?? null;
|
|
3958
|
-
}
|
|
3959
4001
|
async tryLoadDeviceSigningMaterial(userId, roots) {
|
|
3960
4002
|
const path = await importNodeModule$1("node:path");
|
|
3961
4003
|
const candidateDirs = [
|
|
@@ -3964,44 +4006,41 @@ class BuckyOSRuntime {
|
|
|
3964
4006
|
];
|
|
3965
4007
|
for (const dir of Array.from(new Set(candidateDirs))) {
|
|
3966
4008
|
const metadata = await this.readNodeIdentityMetadata(path.join(dir, "node_identity.json"));
|
|
3967
|
-
|
|
3968
|
-
if (!deviceName || deviceName !== userId) {
|
|
4009
|
+
if (!metadata || metadata.deviceName !== userId) {
|
|
3969
4010
|
continue;
|
|
3970
4011
|
}
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
continue;
|
|
3975
|
-
}
|
|
3976
|
-
return {
|
|
3977
|
-
keyPem,
|
|
3978
|
-
issuer: deviceName,
|
|
3979
|
-
subject: deviceName,
|
|
3980
|
-
sourcePath: keyPath
|
|
3981
|
-
};
|
|
4012
|
+
const material = await this.loadDeviceSigningMaterial(dir, metadata);
|
|
4013
|
+
if (material) {
|
|
4014
|
+
return material;
|
|
3982
4015
|
}
|
|
3983
4016
|
}
|
|
3984
4017
|
return null;
|
|
3985
4018
|
}
|
|
3986
|
-
//
|
|
3987
|
-
//
|
|
3988
|
-
|
|
3989
|
-
async deviceKeyPathCandidates(identityDir, deviceDid) {
|
|
4019
|
+
// The device authentication key lives in the identity-roots security dir,
|
|
4020
|
+
// keyed by the device DID.
|
|
4021
|
+
async loadDeviceSigningMaterial(identityDir, metadata) {
|
|
3990
4022
|
const path = await importNodeModule$1("node:path");
|
|
3991
|
-
const
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4023
|
+
const dirName = DID.fromStr(metadata.deviceDid).toFilename();
|
|
4024
|
+
const keyFileName = "authentication.private.pem";
|
|
4025
|
+
const securityRoot = trimToNull$2(getProcessEnv().BUCKYOS_SECURITY_ROOT) ?? path.join(await this.getBuckyOSRootDir(), "security");
|
|
4026
|
+
const keyPaths = [
|
|
4027
|
+
// dev/test layout: security root under the node dir itself
|
|
4028
|
+
path.join(identityDir, "security", dirName, keyFileName),
|
|
4029
|
+
// deployed layout: $BUCKYOS_SECURITY_ROOT or $BUCKYOS_ROOT/security
|
|
4030
|
+
path.join(securityRoot, dirName, keyFileName)
|
|
4031
|
+
];
|
|
4032
|
+
for (const keyPath of keyPaths) {
|
|
4033
|
+
const keyPem = await this.readPemFile(keyPath);
|
|
4034
|
+
if (keyPem) {
|
|
4035
|
+
return {
|
|
4036
|
+
keyPem,
|
|
4037
|
+
issuer: metadata.deviceName,
|
|
4038
|
+
subject: metadata.deviceName,
|
|
4039
|
+
sourcePath: keyPath
|
|
4040
|
+
};
|
|
4001
4041
|
}
|
|
4002
4042
|
}
|
|
4003
|
-
|
|
4004
|
-
return candidates;
|
|
4043
|
+
return null;
|
|
4005
4044
|
}
|
|
4006
4045
|
async tryLoadUserSigningMaterial(userId, roots) {
|
|
4007
4046
|
var _a2;
|
|
@@ -4033,35 +4072,6 @@ class BuckyOSRuntime {
|
|
|
4033
4072
|
}
|
|
4034
4073
|
return null;
|
|
4035
4074
|
}
|
|
4036
|
-
async tryResolveDeviceNameFromSearchRoots(roots) {
|
|
4037
|
-
const path = await importNodeModule$1("node:path");
|
|
4038
|
-
const env = getProcessEnv();
|
|
4039
|
-
const fromEnv = trimToNull$2(env.BUCKYOS_THIS_DEVICE_NAME);
|
|
4040
|
-
if (fromEnv) {
|
|
4041
|
-
return fromEnv;
|
|
4042
|
-
}
|
|
4043
|
-
for (const key of ["BUCKYOS_THIS_DEVICE", "BUCKYOS_THIS_DEVICE_INFO"]) {
|
|
4044
|
-
const raw = trimToNull$2(env[key]);
|
|
4045
|
-
if (!raw) {
|
|
4046
|
-
continue;
|
|
4047
|
-
}
|
|
4048
|
-
try {
|
|
4049
|
-
const parsed = JSON.parse(raw);
|
|
4050
|
-
if (typeof parsed.name === "string" && parsed.name.trim().length > 0) {
|
|
4051
|
-
return parsed.name.trim();
|
|
4052
|
-
}
|
|
4053
|
-
} catch {
|
|
4054
|
-
}
|
|
4055
|
-
}
|
|
4056
|
-
for (const root of roots) {
|
|
4057
|
-
const nodeIdentityPath = path.join(root, "node_identity.json");
|
|
4058
|
-
const deviceName = await this.readDeviceNameFromNodeIdentityPath(nodeIdentityPath);
|
|
4059
|
-
if (deviceName) {
|
|
4060
|
-
return deviceName;
|
|
4061
|
-
}
|
|
4062
|
-
}
|
|
4063
|
-
return null;
|
|
4064
|
-
}
|
|
4065
4075
|
async tryResolveZoneHostFromSearchRoots(roots) {
|
|
4066
4076
|
var _a2;
|
|
4067
4077
|
const fs = await importNodeModule$1("node:fs/promises");
|
|
@@ -4074,16 +4084,9 @@ class BuckyOSRuntime {
|
|
|
4074
4084
|
for (const root of roots) {
|
|
4075
4085
|
const nodeIdentityPath = path.join(root, "node_identity.json");
|
|
4076
4086
|
const metadata = await this.readNodeIdentityMetadata(nodeIdentityPath);
|
|
4077
|
-
if (
|
|
4078
|
-
|
|
4079
|
-
}
|
|
4080
|
-
if (metadata.zoneName) {
|
|
4081
|
-
return metadata.zoneName;
|
|
4082
|
-
}
|
|
4083
|
-
if (!metadata.zoneDid) {
|
|
4084
|
-
continue;
|
|
4087
|
+
if (metadata) {
|
|
4088
|
+
return resolveZoneHostFromDid(metadata.zoneDid);
|
|
4085
4089
|
}
|
|
4086
|
-
return resolveZoneHostFromDid(metadata.zoneDid);
|
|
4087
4090
|
}
|
|
4088
4091
|
for (const root of roots) {
|
|
4089
4092
|
const userConfigPath = path.join(root, "user_config.json");
|
|
@@ -5041,7 +5044,6 @@ class BuckyOSSDK {
|
|
|
5041
5044
|
var _a2;
|
|
5042
5045
|
const finalConfig = this.buildRuntimeConfig(appid, config);
|
|
5043
5046
|
if (this.target !== "node" && isBrowserRuntime() && !config) {
|
|
5044
|
-
localStorage.removeItem("zone_host_name");
|
|
5045
5047
|
let zoneHostName = localStorage.getItem("zone_host_name_v2");
|
|
5046
5048
|
if (zoneHostName) {
|
|
5047
5049
|
finalConfig.zoneHost = zoneHostName;
|
|
@@ -5181,20 +5183,19 @@ class BuckyOSSDK {
|
|
|
5181
5183
|
try {
|
|
5182
5184
|
const verifyHubClient = this.getVerifyHubClient();
|
|
5183
5185
|
verifyHubClient.setSeq(loginNonce);
|
|
5184
|
-
const
|
|
5186
|
+
const response = await verifyHubClient.loginByPassword({
|
|
5185
5187
|
username,
|
|
5186
5188
|
password: passwordHash,
|
|
5187
5189
|
target: resolvedTarget,
|
|
5188
5190
|
login_nonce: loginNonce,
|
|
5189
5191
|
source_url: typeof window !== "undefined" ? window.location.href : void 0
|
|
5190
5192
|
});
|
|
5191
|
-
const normalized = VerifyHubClient.normalizeLoginResponse(accountResponse);
|
|
5192
5193
|
const accountInfo = {
|
|
5193
|
-
user_name:
|
|
5194
|
-
user_id:
|
|
5195
|
-
user_type:
|
|
5196
|
-
session_token:
|
|
5197
|
-
refresh_token:
|
|
5194
|
+
user_name: response.user_info.show_name,
|
|
5195
|
+
user_id: response.user_info.user_id,
|
|
5196
|
+
user_type: response.user_info.user_type,
|
|
5197
|
+
session_token: response.session_token,
|
|
5198
|
+
refresh_token: response.refresh_token
|
|
5198
5199
|
};
|
|
5199
5200
|
if (isBrowserStorageAvailable()) {
|
|
5200
5201
|
saveLocalAccountInfo(appId, accountInfo);
|
|
@@ -5202,7 +5203,7 @@ class BuckyOSSDK {
|
|
|
5202
5203
|
saveBrowserUserInfo({
|
|
5203
5204
|
user_name: accountInfo.user_name,
|
|
5204
5205
|
user_id: accountInfo.user_id,
|
|
5205
|
-
user_type:
|
|
5206
|
+
user_type: response.user_info.user_type
|
|
5206
5207
|
});
|
|
5207
5208
|
}
|
|
5208
5209
|
this.currentAccountInfo = accountInfo;
|
|
@@ -5392,6 +5393,12 @@ class BuckyOSSDK {
|
|
|
5392
5393
|
}
|
|
5393
5394
|
return this.currentRuntime.getAiccClient();
|
|
5394
5395
|
}
|
|
5396
|
+
getAiWorkspaceClient() {
|
|
5397
|
+
if (this.currentRuntime == null) {
|
|
5398
|
+
throw new Error("BuckyOS WebSDK is not initialized,call initBuckyOS first");
|
|
5399
|
+
}
|
|
5400
|
+
return this.currentRuntime.getAiWorkspaceClient();
|
|
5401
|
+
}
|
|
5395
5402
|
getMsgQueueClient() {
|
|
5396
5403
|
if (this.currentRuntime == null) {
|
|
5397
5404
|
throw new Error("BuckyOS WebSDK is not initialized,call initBuckyOS first");
|
|
@@ -5479,16 +5486,7 @@ class BuckyOSSDK {
|
|
|
5479
5486
|
}
|
|
5480
5487
|
const doc = await response.json();
|
|
5481
5488
|
const hostname = typeof doc.hostname === "string" ? doc.hostname.trim() : "";
|
|
5482
|
-
|
|
5483
|
-
return hostname;
|
|
5484
|
-
}
|
|
5485
|
-
if (typeof doc.id === "string") {
|
|
5486
|
-
const match = doc.id.match(/^did:web:([^/?#]+)/);
|
|
5487
|
-
if (match && match[1]) {
|
|
5488
|
-
return match[1];
|
|
5489
|
-
}
|
|
5490
|
-
}
|
|
5491
|
-
return null;
|
|
5489
|
+
return hostname.length > 0 ? hostname : null;
|
|
5492
5490
|
} catch {
|
|
5493
5491
|
return null;
|
|
5494
5492
|
}
|
|
@@ -5584,6 +5582,7 @@ function createSDKModule(target) {
|
|
|
5584
5582
|
getTaskManagerClient: sdk.getTaskManagerClient.bind(sdk),
|
|
5585
5583
|
getWorkflowClient: sdk.getWorkflowClient.bind(sdk),
|
|
5586
5584
|
getAiccClient: sdk.getAiccClient.bind(sdk),
|
|
5585
|
+
getAiWorkspaceClient: sdk.getAiWorkspaceClient.bind(sdk),
|
|
5587
5586
|
getMsgQueueClient: sdk.getMsgQueueClient.bind(sdk),
|
|
5588
5587
|
getMsgCenterClient: sdk.getMsgCenterClient.bind(sdk),
|
|
5589
5588
|
getRepoClient: sdk.getRepoClient.bind(sdk)
|
|
@@ -22178,7 +22177,7 @@ class AbstractProvider {
|
|
|
22178
22177
|
request.body = { data, sender };
|
|
22179
22178
|
}
|
|
22180
22179
|
this.emit("debug", { action: "sendCcipReadFetchRequest", request, index: i, urls });
|
|
22181
|
-
let
|
|
22180
|
+
let errorMessage2 = "unknown error";
|
|
22182
22181
|
let resp;
|
|
22183
22182
|
try {
|
|
22184
22183
|
resp = await request.send();
|
|
@@ -22194,13 +22193,13 @@ class AbstractProvider {
|
|
|
22194
22193
|
return result.data;
|
|
22195
22194
|
}
|
|
22196
22195
|
if (result.message) {
|
|
22197
|
-
|
|
22196
|
+
errorMessage2 = result.message;
|
|
22198
22197
|
}
|
|
22199
22198
|
this.emit("debug", { action: "receiveCcipReadFetchError", request, result });
|
|
22200
22199
|
} catch (error) {
|
|
22201
22200
|
}
|
|
22202
|
-
assert(resp.statusCode < 400 || resp.statusCode >= 500, `response not found during CCIP fetch: ${
|
|
22203
|
-
errorMessages.push(
|
|
22201
|
+
assert(resp.statusCode < 400 || resp.statusCode >= 500, `response not found during CCIP fetch: ${errorMessage2}`, "OFFCHAIN_FAULT", { reason: "404_MISSING_RESOURCE", transaction: tx, info: { url, errorMessage: errorMessage2 } });
|
|
22202
|
+
errorMessages.push(errorMessage2);
|
|
22204
22203
|
}
|
|
22205
22204
|
assert(false, `error encountered during CCIP fetch: ${errorMessages.map((m) => JSON.stringify(m)).join(", ")}`, "OFFCHAIN_FAULT", {
|
|
22206
22205
|
reason: "500_SERVER_ERROR",
|
|
@@ -27581,7 +27580,9 @@ function getWorkerBlobUrl() {
|
|
|
27581
27580
|
function isHashWorkerAvailable() {
|
|
27582
27581
|
return typeof Worker !== "undefined" && typeof Blob !== "undefined" && typeof URL !== "undefined" && typeof URL.createObjectURL === "function" && typeof crypto !== "undefined" && typeof crypto.subtle !== "undefined";
|
|
27583
27582
|
}
|
|
27584
|
-
function hashFileInWorker(file, chunkSize) {
|
|
27583
|
+
function hashFileInWorker(file, chunkSize, signal) {
|
|
27584
|
+
let cancel = () => {
|
|
27585
|
+
};
|
|
27585
27586
|
let progressCb = null;
|
|
27586
27587
|
let cumulativeBytes = 0;
|
|
27587
27588
|
const chunks = [];
|
|
@@ -27593,6 +27594,16 @@ function hashFileInWorker(file, chunkSize) {
|
|
|
27593
27594
|
reject(new Error("Failed to create hash worker"));
|
|
27594
27595
|
return;
|
|
27595
27596
|
}
|
|
27597
|
+
cancel = () => {
|
|
27598
|
+
worker.terminate();
|
|
27599
|
+
signal == null ? void 0 : signal.removeEventListener("abort", cancel);
|
|
27600
|
+
reject(new Error("Hash cancelled"));
|
|
27601
|
+
};
|
|
27602
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
27603
|
+
cancel();
|
|
27604
|
+
return;
|
|
27605
|
+
}
|
|
27606
|
+
signal == null ? void 0 : signal.addEventListener("abort", cancel, { once: true });
|
|
27596
27607
|
worker.onmessage = (e) => {
|
|
27597
27608
|
const msg = e.data;
|
|
27598
27609
|
if (msg.type === "chunk") {
|
|
@@ -27607,14 +27618,17 @@ function hashFileInWorker(file, chunkSize) {
|
|
|
27607
27618
|
if (progressCb)
|
|
27608
27619
|
progressCb(cumulativeBytes);
|
|
27609
27620
|
} else if (msg.type === "done") {
|
|
27621
|
+
signal == null ? void 0 : signal.removeEventListener("abort", cancel);
|
|
27610
27622
|
worker.terminate();
|
|
27611
27623
|
resolve(chunks);
|
|
27612
27624
|
} else if (msg.type === "error") {
|
|
27625
|
+
signal == null ? void 0 : signal.removeEventListener("abort", cancel);
|
|
27613
27626
|
worker.terminate();
|
|
27614
27627
|
reject(new Error(msg.message ?? "Worker hash error"));
|
|
27615
27628
|
}
|
|
27616
27629
|
};
|
|
27617
27630
|
worker.onerror = (err) => {
|
|
27631
|
+
signal == null ? void 0 : signal.removeEventListener("abort", cancel);
|
|
27618
27632
|
worker.terminate();
|
|
27619
27633
|
reject(new Error(err.message ?? "Worker error"));
|
|
27620
27634
|
};
|
|
@@ -27622,6 +27636,7 @@ function hashFileInWorker(file, chunkSize) {
|
|
|
27622
27636
|
});
|
|
27623
27637
|
return {
|
|
27624
27638
|
result,
|
|
27639
|
+
cancel: () => cancel(),
|
|
27625
27640
|
onProgress(cb) {
|
|
27626
27641
|
progressCb = cb;
|
|
27627
27642
|
}
|
|
@@ -27664,6 +27679,7 @@ const browserProvider = {
|
|
|
27664
27679
|
},
|
|
27665
27680
|
pickFiles(options) {
|
|
27666
27681
|
return new Promise((resolve, reject) => {
|
|
27682
|
+
var _a2, _b;
|
|
27667
27683
|
const input = document.createElement("input");
|
|
27668
27684
|
input.type = "file";
|
|
27669
27685
|
if (options.mode === "single_dir") {
|
|
@@ -27679,27 +27695,44 @@ const browserProvider = {
|
|
|
27679
27695
|
input.accept = options.accept.join(",");
|
|
27680
27696
|
}
|
|
27681
27697
|
let settled = false;
|
|
27682
|
-
|
|
27698
|
+
const cleanup = () => {
|
|
27699
|
+
var _a3;
|
|
27700
|
+
window.removeEventListener("focus", onFocus);
|
|
27701
|
+
(_a3 = options.signal) == null ? void 0 : _a3.removeEventListener("abort", onAbort);
|
|
27702
|
+
};
|
|
27703
|
+
const fail2 = (error) => {
|
|
27683
27704
|
if (settled)
|
|
27684
27705
|
return;
|
|
27685
27706
|
settled = true;
|
|
27707
|
+
cleanup();
|
|
27708
|
+
reject(error);
|
|
27709
|
+
};
|
|
27710
|
+
const onAbort = () => fail2(new NdmError("USER_CANCELLED", "Import cancelled"));
|
|
27711
|
+
const onFocus = () => {
|
|
27712
|
+
setTimeout(() => {
|
|
27713
|
+
if (!settled)
|
|
27714
|
+
fail2(new NdmError("USER_CANCELLED", "User cancelled file selection"));
|
|
27715
|
+
}, 500);
|
|
27716
|
+
};
|
|
27717
|
+
input.addEventListener("change", () => {
|
|
27718
|
+
if (settled)
|
|
27719
|
+
return;
|
|
27686
27720
|
const files = input.files;
|
|
27687
27721
|
if (!files || files.length === 0) {
|
|
27688
|
-
|
|
27722
|
+
fail2(new NdmError(options.mode === "single_dir" ? "EMPTY_DIRECTORY_UNAVAILABLE" : "USER_CANCELLED", options.mode === "single_dir" ? "FileList cannot represent an empty directory; use a directory-tree provider" : "No files selected"));
|
|
27689
27723
|
return;
|
|
27690
27724
|
}
|
|
27725
|
+
settled = true;
|
|
27726
|
+
cleanup();
|
|
27691
27727
|
resolve(Array.from(files));
|
|
27692
27728
|
});
|
|
27693
|
-
|
|
27694
|
-
setTimeout(() => {
|
|
27695
|
-
if (!settled) {
|
|
27696
|
-
settled = true;
|
|
27697
|
-
reject(new NdmError("USER_CANCELLED", "User cancelled file selection"));
|
|
27698
|
-
}
|
|
27699
|
-
window.removeEventListener("focus", onFocus);
|
|
27700
|
-
}, 500);
|
|
27701
|
-
};
|
|
27729
|
+
input.addEventListener("cancel", onAbort);
|
|
27702
27730
|
window.addEventListener("focus", onFocus);
|
|
27731
|
+
if ((_a2 = options.signal) == null ? void 0 : _a2.aborted) {
|
|
27732
|
+
onAbort();
|
|
27733
|
+
return;
|
|
27734
|
+
}
|
|
27735
|
+
(_b = options.signal) == null ? void 0 : _b.addEventListener("abort", onAbort, { once: true });
|
|
27703
27736
|
input.click();
|
|
27704
27737
|
});
|
|
27705
27738
|
}
|
|
@@ -27772,7 +27805,8 @@ async function callStoreApi(methodName, requestBody, options) {
|
|
|
27772
27805
|
method: "POST",
|
|
27773
27806
|
headers,
|
|
27774
27807
|
body: JSON.stringify(requestBody),
|
|
27775
|
-
credentials: (options == null ? void 0 : options.credentials) ?? "include"
|
|
27808
|
+
credentials: (options == null ? void 0 : options.credentials) ?? "include",
|
|
27809
|
+
signal: options == null ? void 0 : options.signal
|
|
27776
27810
|
});
|
|
27777
27811
|
if (response.status === 204) {
|
|
27778
27812
|
await ((_a2 = response.body) == null ? void 0 : _a2.cancel());
|
|
@@ -27806,7 +27840,8 @@ async function getZoneGatewayJson(pathWithQuery, options) {
|
|
|
27806
27840
|
const response = await fetcher(`${endpoint}${pathWithQuery}`, {
|
|
27807
27841
|
method: "GET",
|
|
27808
27842
|
headers,
|
|
27809
|
-
credentials: (options == null ? void 0 : options.credentials) ?? "include"
|
|
27843
|
+
credentials: (options == null ? void 0 : options.credentials) ?? "include",
|
|
27844
|
+
signal: options == null ? void 0 : options.signal
|
|
27810
27845
|
});
|
|
27811
27846
|
const contentType = response.headers.get("content-type") ?? "";
|
|
27812
27847
|
const isJsonResponse = contentType.includes("application/json");
|
|
@@ -27911,7 +27946,8 @@ async function debugDumpExpandState$1(request, options) {
|
|
|
27911
27946
|
async function anchorState$1(request, options) {
|
|
27912
27947
|
return callStoreApi("anchor_state", request, options);
|
|
27913
27948
|
}
|
|
27914
|
-
async function materializeFile(file, chunkSize = DEFAULT_CHUNK_SIZE) {
|
|
27949
|
+
async function materializeFile(file, chunkSize = DEFAULT_CHUNK_SIZE, signal) {
|
|
27950
|
+
throwIfCancelled(signal);
|
|
27915
27951
|
const fileSize = file.size;
|
|
27916
27952
|
const chunks = [];
|
|
27917
27953
|
if (fileSize <= chunkSize) {
|
|
@@ -27921,12 +27957,14 @@ async function materializeFile(file, chunkSize = DEFAULT_CHUNK_SIZE) {
|
|
|
27921
27957
|
const chunkIdStr = chunkId.toString();
|
|
27922
27958
|
chunks.push({ chunkId: chunkIdStr, offset: 0, length: buf.length, uploaded: false });
|
|
27923
27959
|
const fileObj2 = new FileObject(file.name, fileSize, chunkIdStr);
|
|
27924
|
-
const [objId2] = fileObj2.genObjId();
|
|
27925
|
-
|
|
27960
|
+
const [objId2, objData2] = fileObj2.genObjId();
|
|
27961
|
+
throwIfCancelled(signal);
|
|
27962
|
+
return { objectId: objId2.toString(), chunks, fileObject: fileObj2.toJSON(), objects: [{ obj_id: objId2.toString(), obj_data: objData2 }] };
|
|
27926
27963
|
}
|
|
27927
27964
|
const chunkList = new SimpleChunkList();
|
|
27928
27965
|
let offset = 0;
|
|
27929
27966
|
while (offset < fileSize) {
|
|
27967
|
+
throwIfCancelled(signal);
|
|
27930
27968
|
const end = Math.min(offset + chunkSize, fileSize);
|
|
27931
27969
|
const slice = new Uint8Array(await file.slice(offset, end).arrayBuffer());
|
|
27932
27970
|
const hash2 = sha256Bytes(slice);
|
|
@@ -27935,29 +27973,42 @@ async function materializeFile(file, chunkSize = DEFAULT_CHUNK_SIZE) {
|
|
|
27935
27973
|
chunks.push({ chunkId: chunkId.toString(), offset, length: slice.length, uploaded: false });
|
|
27936
27974
|
offset = end;
|
|
27937
27975
|
}
|
|
27938
|
-
const [chunkListObjId] = chunkList.genObjId();
|
|
27976
|
+
const [chunkListObjId, chunkListData] = chunkList.genObjId();
|
|
27939
27977
|
const fileObj = new FileObject(file.name, fileSize, chunkListObjId.toString());
|
|
27940
|
-
const [objId] = fileObj.genObjId();
|
|
27941
|
-
|
|
27942
|
-
|
|
27943
|
-
|
|
27944
|
-
|
|
27945
|
-
|
|
27978
|
+
const [objId, objData] = fileObj.genObjId();
|
|
27979
|
+
throwIfCancelled(signal);
|
|
27980
|
+
return { objectId: objId.toString(), chunks, fileObject: fileObj.toJSON(), objects: [
|
|
27981
|
+
{ obj_id: chunkListObjId.toString(), obj_data: chunkListData },
|
|
27982
|
+
{ obj_id: objId.toString(), obj_data: objData }
|
|
27983
|
+
] };
|
|
27984
|
+
}
|
|
27985
|
+
async function materializeFileViaWorker(file, onHashProgress, chunkSize = DEFAULT_CHUNK_SIZE, signal) {
|
|
27986
|
+
if (!isHashWorkerAvailable() || file.size === 0) {
|
|
27987
|
+
const result = await materializeFile(file, chunkSize, signal);
|
|
27988
|
+
onHashProgress == null ? void 0 : onHashProgress(file.size);
|
|
27989
|
+
return result;
|
|
27946
27990
|
}
|
|
27947
27991
|
let hashResults;
|
|
27992
|
+
let timer;
|
|
27993
|
+
const worker = hashFileInWorker(file, chunkSize, signal);
|
|
27948
27994
|
try {
|
|
27949
|
-
|
|
27950
|
-
|
|
27951
|
-
session.onProgress(onHashProgress);
|
|
27952
|
-
}
|
|
27953
|
-
const WORKER_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
27995
|
+
if (onHashProgress)
|
|
27996
|
+
worker.onProgress(onHashProgress);
|
|
27954
27997
|
const timeout = new Promise((_, reject) => {
|
|
27955
|
-
setTimeout(() =>
|
|
27998
|
+
timer = setTimeout(() => {
|
|
27999
|
+
worker.cancel();
|
|
28000
|
+
reject(new Error("hash worker timeout"));
|
|
28001
|
+
}, 5 * 60 * 1e3);
|
|
27956
28002
|
});
|
|
27957
|
-
hashResults = await Promise.race([
|
|
28003
|
+
hashResults = await Promise.race([worker.result, timeout]);
|
|
27958
28004
|
} catch {
|
|
27959
|
-
|
|
28005
|
+
throwIfCancelled(signal);
|
|
28006
|
+
return materializeFile(file, chunkSize, signal);
|
|
28007
|
+
} finally {
|
|
28008
|
+
if (timer)
|
|
28009
|
+
clearTimeout(timer);
|
|
27960
28010
|
}
|
|
28011
|
+
throwIfCancelled(signal);
|
|
27961
28012
|
const fileSize = file.size;
|
|
27962
28013
|
const chunks = [];
|
|
27963
28014
|
if (hashResults.length === 1) {
|
|
@@ -27966,8 +28017,9 @@ async function materializeFileViaWorker(file, onHashProgress, chunkSize = DEFAUL
|
|
|
27966
28017
|
const chunkIdStr = chunkId.toString();
|
|
27967
28018
|
chunks.push({ chunkId: chunkIdStr, offset: 0, length: r.length, uploaded: false });
|
|
27968
28019
|
const fileObj2 = new FileObject(file.name, fileSize, chunkIdStr);
|
|
27969
|
-
const [objId2] = fileObj2.genObjId();
|
|
27970
|
-
|
|
28020
|
+
const [objId2, objData2] = fileObj2.genObjId();
|
|
28021
|
+
throwIfCancelled(signal);
|
|
28022
|
+
return { objectId: objId2.toString(), chunks, fileObject: fileObj2.toJSON(), objects: [{ obj_id: objId2.toString(), obj_data: objData2 }] };
|
|
27971
28023
|
}
|
|
27972
28024
|
const chunkList = new SimpleChunkList();
|
|
27973
28025
|
for (const r of hashResults) {
|
|
@@ -27975,10 +28027,14 @@ async function materializeFileViaWorker(file, onHashProgress, chunkSize = DEFAUL
|
|
|
27975
28027
|
chunkList.appendChunk(chunkId);
|
|
27976
28028
|
chunks.push({ chunkId: chunkId.toString(), offset: r.offset, length: r.length, uploaded: false });
|
|
27977
28029
|
}
|
|
27978
|
-
const [chunkListObjId] = chunkList.genObjId();
|
|
28030
|
+
const [chunkListObjId, chunkListData] = chunkList.genObjId();
|
|
27979
28031
|
const fileObj = new FileObject(file.name, fileSize, chunkListObjId.toString());
|
|
27980
|
-
const [objId] = fileObj.genObjId();
|
|
27981
|
-
|
|
28032
|
+
const [objId, objData] = fileObj.genObjId();
|
|
28033
|
+
throwIfCancelled(signal);
|
|
28034
|
+
return { objectId: objId.toString(), chunks, fileObject: fileObj.toJSON(), objects: [
|
|
28035
|
+
{ obj_id: chunkListObjId.toString(), obj_data: chunkListData },
|
|
28036
|
+
{ obj_id: objId.toString(), obj_data: objData }
|
|
28037
|
+
] };
|
|
27982
28038
|
}
|
|
27983
28039
|
function buildFileObjectFromContentId(name, size, contentId) {
|
|
27984
28040
|
const fileObj = new FileObject(name, size, contentId);
|
|
@@ -28000,27 +28056,21 @@ function resolveImportLookupEndpoint() {
|
|
|
28000
28056
|
return void 0;
|
|
28001
28057
|
}
|
|
28002
28058
|
async function tryCalculateQcidFromFile(file) {
|
|
28003
|
-
|
|
28004
|
-
if (fileSize < MIN_QCID_FILE_SIZE) {
|
|
28005
|
-
return null;
|
|
28006
|
-
}
|
|
28007
|
-
const beginBytes = new Uint8Array(await file.slice(0, QCID_HASH_PIECE_SIZE).arrayBuffer());
|
|
28008
|
-
const midOffset = Math.floor(fileSize / 2);
|
|
28009
|
-
const midBytes = new Uint8Array(
|
|
28010
|
-
await file.slice(midOffset, midOffset + QCID_HASH_PIECE_SIZE).arrayBuffer()
|
|
28011
|
-
);
|
|
28012
|
-
const combined = new Uint8Array(beginBytes.length + midBytes.length);
|
|
28013
|
-
combined.set(beginBytes, 0);
|
|
28014
|
-
combined.set(midBytes, beginBytes.length);
|
|
28015
|
-
const hash2 = sha256Bytes(combined);
|
|
28016
|
-
return ChunkId.fromMixHashResult(fileSize, hash2, "qcid").toString();
|
|
28059
|
+
return file.size < MIN_QCID_FILE_SIZE ? null : calculateQcidFromFile(file);
|
|
28017
28060
|
}
|
|
28018
28061
|
async function calculateQcidFromFile(file) {
|
|
28019
|
-
const
|
|
28020
|
-
|
|
28021
|
-
|
|
28062
|
+
const fileSize = file.size;
|
|
28063
|
+
let sampled;
|
|
28064
|
+
if (fileSize < MIN_QCID_FILE_SIZE) {
|
|
28065
|
+
sampled = new Uint8Array(await file.arrayBuffer());
|
|
28066
|
+
} else {
|
|
28067
|
+
sampled = new Uint8Array(QCID_HASH_PIECE_SIZE * 3);
|
|
28068
|
+
const offsets = [0, Math.floor((fileSize - QCID_HASH_PIECE_SIZE) / 2), fileSize - QCID_HASH_PIECE_SIZE];
|
|
28069
|
+
for (let index = 0; index < offsets.length; index++) {
|
|
28070
|
+
sampled.set(new Uint8Array(await file.slice(offsets[index], offsets[index] + QCID_HASH_PIECE_SIZE).arrayBuffer()), index * QCID_HASH_PIECE_SIZE);
|
|
28071
|
+
}
|
|
28022
28072
|
}
|
|
28023
|
-
return qcid;
|
|
28073
|
+
return ChunkId.fromMixHashResult(fileSize, sha256Bytes(sampled), "qcid").toString();
|
|
28024
28074
|
}
|
|
28025
28075
|
function extractLookupContentId(response, quickHash) {
|
|
28026
28076
|
const body = response;
|
|
@@ -28046,81 +28096,75 @@ function extractLookupContentId(response, quickHash) {
|
|
|
28046
28096
|
}
|
|
28047
28097
|
return void 0;
|
|
28048
28098
|
}
|
|
28049
|
-
async function lookupFileByQcid(file) {
|
|
28050
|
-
const endpoint = resolveImportLookupEndpoint();
|
|
28051
|
-
if (!endpoint)
|
|
28099
|
+
async function lookupFileByQcid(file, options, warnings) {
|
|
28100
|
+
const endpoint = options.endpoint ?? resolveImportLookupEndpoint();
|
|
28101
|
+
if (!endpoint)
|
|
28052
28102
|
return null;
|
|
28053
|
-
}
|
|
28054
28103
|
const qcid = await tryCalculateQcidFromFile(file);
|
|
28055
|
-
|
|
28104
|
+
throwIfCancelled(options.signal);
|
|
28105
|
+
if (!qcid)
|
|
28056
28106
|
return null;
|
|
28057
|
-
|
|
28058
|
-
|
|
28059
|
-
|
|
28060
|
-
|
|
28061
|
-
|
|
28062
|
-
|
|
28063
|
-
|
|
28064
|
-
|
|
28065
|
-
}
|
|
28066
|
-
);
|
|
28067
|
-
const contentId = extractLookupContentId(response, qcid);
|
|
28068
|
-
if (!contentId) {
|
|
28069
|
-
continue;
|
|
28070
|
-
}
|
|
28071
|
-
return {
|
|
28072
|
-
...buildFileObjectFromContentId(file.name, file.size, contentId),
|
|
28073
|
-
locality: "store"
|
|
28074
|
-
};
|
|
28075
|
-
} catch (error) {
|
|
28076
|
-
if (error instanceof NdmStoreApiError && error.status === 404) {
|
|
28077
|
-
continue;
|
|
28078
|
-
}
|
|
28107
|
+
try {
|
|
28108
|
+
const response = await lookupObject({ scope: "app", quick_hash: qcid }, { ...options, endpoint });
|
|
28109
|
+
if (response.reusable !== true || !("state" in response) || !["completed", "same_as", "local_link"].includes(response.state))
|
|
28110
|
+
return null;
|
|
28111
|
+
if (response.chunk_size !== file.size)
|
|
28112
|
+
return null;
|
|
28113
|
+
const contentId = extractLookupContentId(response, qcid);
|
|
28114
|
+
if (!contentId || !(ObjId.fromString(contentId).isChunk() || ObjId.fromString(contentId).isChunkList()) || contentId.startsWith("qcid:"))
|
|
28079
28115
|
return null;
|
|
28116
|
+
return { ...buildFileObjectFromContentId(file.name, file.size, contentId), locality: "store", qcid };
|
|
28117
|
+
} catch (error) {
|
|
28118
|
+
throwIfCancelled(options.signal);
|
|
28119
|
+
if (!(error instanceof NdmStoreApiError && error.status === 404)) {
|
|
28120
|
+
warnings.push(`QCID lookup for ${file.name}: ${errorMessage(error)}`);
|
|
28080
28121
|
}
|
|
28122
|
+
return null;
|
|
28123
|
+
}
|
|
28124
|
+
}
|
|
28125
|
+
function validateName(name) {
|
|
28126
|
+
if (!name || name === "." || name === ".." || /[\\/\x00-\x1f]/.test(name) || /^[a-z]:/i.test(name)) {
|
|
28127
|
+
throw new NdmError("INVALID_IMPORT_PATH", `Invalid file or directory name: ${name}`);
|
|
28081
28128
|
}
|
|
28082
|
-
|
|
28129
|
+
}
|
|
28130
|
+
function validatePath(path) {
|
|
28131
|
+
const parts = path.split("/");
|
|
28132
|
+
parts.forEach(validateName);
|
|
28133
|
+
return parts;
|
|
28083
28134
|
}
|
|
28084
28135
|
function buildDirTree(files, fileObjects) {
|
|
28085
|
-
|
|
28086
|
-
|
|
28087
|
-
const
|
|
28088
|
-
|
|
28089
|
-
|
|
28090
|
-
|
|
28091
|
-
|
|
28092
|
-
|
|
28093
|
-
|
|
28094
|
-
|
|
28095
|
-
|
|
28096
|
-
|
|
28097
|
-
|
|
28098
|
-
|
|
28099
|
-
|
|
28100
|
-
|
|
28101
|
-
|
|
28102
|
-
|
|
28103
|
-
|
|
28104
|
-
|
|
28105
|
-
|
|
28106
|
-
|
|
28107
|
-
|
|
28108
|
-
|
|
28109
|
-
|
|
28110
|
-
|
|
28111
|
-
children: []
|
|
28112
|
-
};
|
|
28113
|
-
dirMap.set(dirPath, dir);
|
|
28114
|
-
currentDir.children.push(dir);
|
|
28136
|
+
if (files.length === 0)
|
|
28137
|
+
throw new NdmError("EMPTY_DIRECTORY_UNAVAILABLE", "FileList cannot represent an empty directory; use importDirectory with directory nodes");
|
|
28138
|
+
const paths = files.map((file) => validatePath(file.webkitRelativePath || file.name));
|
|
28139
|
+
if (paths.some((parts) => parts.length < 2 || parts[0] !== paths[0][0])) {
|
|
28140
|
+
throw new NdmError("INVALID_IMPORT_PATH", "Folder selection must contain one root directory in webkitRelativePath");
|
|
28141
|
+
}
|
|
28142
|
+
const root = { kind: "dir", objectId: "", name: paths[0][0], children: [] };
|
|
28143
|
+
for (let index = 0; index < paths.length; index++) {
|
|
28144
|
+
const parts = paths[index].slice(1);
|
|
28145
|
+
let dir = root;
|
|
28146
|
+
for (let i = 0; i < parts.length; i++) {
|
|
28147
|
+
const name = parts[i];
|
|
28148
|
+
const existing = dir.children.find((child) => child.name === name);
|
|
28149
|
+
if (i === parts.length - 1) {
|
|
28150
|
+
if (existing)
|
|
28151
|
+
throw new NdmError("IMPORT_PATH_CONFLICT", `Duplicate file or directory: ${paths[index].join("/")}`);
|
|
28152
|
+
if (name !== fileObjects[index].name)
|
|
28153
|
+
throw new NdmError("INVALID_IMPORT_PATH", "Relative path basename must match File.name");
|
|
28154
|
+
dir.children.push(fileObjects[index]);
|
|
28155
|
+
} else {
|
|
28156
|
+
if ((existing == null ? void 0 : existing.kind) === "file")
|
|
28157
|
+
throw new NdmError("IMPORT_PATH_CONFLICT", `File used as directory: ${name}`);
|
|
28158
|
+
const child = existing ?? { kind: "dir", objectId: "", name, relativePath: parts.slice(0, i + 1).join("/"), children: [] };
|
|
28159
|
+
if (!existing)
|
|
28160
|
+
dir.children.push(child);
|
|
28161
|
+
dir = child;
|
|
28115
28162
|
}
|
|
28116
|
-
currentDir = dir;
|
|
28117
28163
|
}
|
|
28118
|
-
currentDir.children.push(fileObj);
|
|
28119
28164
|
}
|
|
28120
|
-
computeDirObjectIds(root);
|
|
28121
28165
|
return root;
|
|
28122
28166
|
}
|
|
28123
|
-
function computeDirObjectIds(dir) {
|
|
28167
|
+
function computeDirObjectIds(dir, manifest) {
|
|
28124
28168
|
const ndnDir = new DirObject(dir.name);
|
|
28125
28169
|
if (dir.children) {
|
|
28126
28170
|
for (const child of dir.children) {
|
|
@@ -28130,13 +28174,14 @@ function computeDirObjectIds(dir) {
|
|
|
28130
28174
|
}
|
|
28131
28175
|
ndnDir.addFile(child.name, child._ndnFileObject, child.size);
|
|
28132
28176
|
} else {
|
|
28133
|
-
const childState = computeDirObjectIds(child);
|
|
28177
|
+
const childState = computeDirObjectIds(child, manifest);
|
|
28134
28178
|
ndnDir.addDirectory(child.name, ObjId.fromString(childState.objectId), childState.totalSize);
|
|
28135
28179
|
}
|
|
28136
28180
|
}
|
|
28137
28181
|
}
|
|
28138
|
-
const [objId] = ndnDir.genObjId();
|
|
28182
|
+
const [objId, objData] = ndnDir.genObjId();
|
|
28139
28183
|
dir.objectId = objId.toString();
|
|
28184
|
+
manifest.set(dir.objectId, { obj_id: dir.objectId, obj_data: objData });
|
|
28140
28185
|
return {
|
|
28141
28186
|
objectId: dir.objectId,
|
|
28142
28187
|
totalSize: ndnDir.total_size,
|
|
@@ -28225,18 +28270,63 @@ function collectSummary(items) {
|
|
|
28225
28270
|
return { totalObjects: totalFiles + totalDirs, totalFiles, totalDirs, totalBytes };
|
|
28226
28271
|
}
|
|
28227
28272
|
async function pickupAndImport(options) {
|
|
28273
|
+
const provider = options.provider ?? currentProvider;
|
|
28274
|
+
const caps = provider.getCapabilities();
|
|
28275
|
+
if (options.mode === "single_dir" && !caps.canPickDirectory)
|
|
28276
|
+
throw new NdmError("DIRECTORY_NOT_SUPPORTED");
|
|
28277
|
+
if (options.mode === "mixed" && !caps.canPickMixed)
|
|
28278
|
+
throw new NdmError("MODE_NOT_SUPPORTED_IN_RUNTIME");
|
|
28279
|
+
throwIfCancelled(options.signal);
|
|
28280
|
+
const files = await provider.pickFiles(options);
|
|
28281
|
+
return importFiles(files, options);
|
|
28282
|
+
}
|
|
28283
|
+
async function importFiles(selectedFiles, options) {
|
|
28284
|
+
return importSelectedFiles(selectedFiles, options);
|
|
28285
|
+
}
|
|
28286
|
+
async function importDirectory(tree, options = {}) {
|
|
28287
|
+
return importSelectedFiles([], { ...options, mode: "single_dir" }, tree);
|
|
28288
|
+
}
|
|
28289
|
+
async function importSelectedFiles(selectedFiles, options, tree) {
|
|
28228
28290
|
var _a2;
|
|
28229
|
-
|
|
28230
|
-
|
|
28231
|
-
|
|
28232
|
-
|
|
28233
|
-
|
|
28234
|
-
|
|
28235
|
-
|
|
28236
|
-
|
|
28237
|
-
|
|
28238
|
-
|
|
28239
|
-
|
|
28291
|
+
throwIfCancelled(options.signal);
|
|
28292
|
+
const files = [...selectedFiles];
|
|
28293
|
+
const treePaths = [];
|
|
28294
|
+
if (tree) {
|
|
28295
|
+
const walk = (dir, parent) => {
|
|
28296
|
+
validateName(dir.name);
|
|
28297
|
+
const names = /* @__PURE__ */ new Set();
|
|
28298
|
+
for (const child of dir.children) {
|
|
28299
|
+
const name = child.kind === "file" ? child.file.name : child.name;
|
|
28300
|
+
validateName(name);
|
|
28301
|
+
if (names.has(name))
|
|
28302
|
+
throw new NdmError("IMPORT_PATH_CONFLICT", `Duplicate child: ${parent}/${name}`);
|
|
28303
|
+
names.add(name);
|
|
28304
|
+
if (child.kind === "file") {
|
|
28305
|
+
files.push(child.file);
|
|
28306
|
+
treePaths.push(`${parent}/${name}`);
|
|
28307
|
+
} else
|
|
28308
|
+
walk(child, `${parent}/${child.name}`);
|
|
28309
|
+
}
|
|
28310
|
+
};
|
|
28311
|
+
walk(tree, tree.name);
|
|
28312
|
+
}
|
|
28313
|
+
if (!tree && files.length === 0)
|
|
28314
|
+
throw new NdmError(options.mode === "single_dir" ? "EMPTY_DIRECTORY_UNAVAILABLE" : "USER_CANCELLED", options.mode === "single_dir" ? "FileList cannot represent empty directories; use importDirectory" : "No files selected");
|
|
28315
|
+
if (options.mode === "single_file" && files.length !== 1)
|
|
28316
|
+
throw new NdmError("INVALID_IMPORT_PATH", "single_file requires exactly one file");
|
|
28317
|
+
files.forEach((file) => {
|
|
28318
|
+
validateName(file.name);
|
|
28319
|
+
if (file.webkitRelativePath)
|
|
28320
|
+
validatePath(file.webkitRelativePath);
|
|
28321
|
+
});
|
|
28322
|
+
if (!tree && options.mode === "single_dir")
|
|
28323
|
+
buildDirTree(files, files.map((file) => ({ kind: "file", objectId: "", name: file.name, size: file.size })));
|
|
28324
|
+
const warnings = [];
|
|
28325
|
+
if (!tree && options.mode === "single_dir")
|
|
28326
|
+
warnings.push("FileList selections cannot preserve empty directories");
|
|
28327
|
+
const manifest = /* @__PURE__ */ new Map();
|
|
28328
|
+
const qcidLinks = [];
|
|
28329
|
+
const requestOptions = { endpoint: options.endpoint, sessionToken: options.sessionToken, fetcher: options.fetcher, headers: options.headers, signal: options.signal };
|
|
28240
28330
|
const fileObjects = [];
|
|
28241
28331
|
const objectStates = /* @__PURE__ */ new Map();
|
|
28242
28332
|
let allFilesAlreadyStored = true;
|
|
@@ -28244,11 +28334,12 @@ async function pickupAndImport(options) {
|
|
|
28244
28334
|
const fileCount = files.length;
|
|
28245
28335
|
for (let fi = 0; fi < files.length; fi++) {
|
|
28246
28336
|
const file = files[fi];
|
|
28247
|
-
|
|
28337
|
+
throwIfCancelled(options.signal);
|
|
28338
|
+
const relativePath = treePaths[fi] || file.webkitRelativePath || void 0;
|
|
28248
28339
|
if (onProgress) {
|
|
28249
28340
|
onProgress({ phase: "qcid_lookup", fileIndex: fi, fileCount, fileName: file.name, fileTotalBytes: file.size });
|
|
28250
28341
|
}
|
|
28251
|
-
const lookupHit = await lookupFileByQcid(file);
|
|
28342
|
+
const lookupHit = await lookupFileByQcid(file, requestOptions, warnings);
|
|
28252
28343
|
let materialized = null;
|
|
28253
28344
|
if (!lookupHit) {
|
|
28254
28345
|
if (onProgress) {
|
|
@@ -28258,12 +28349,25 @@ async function pickupAndImport(options) {
|
|
|
28258
28349
|
file,
|
|
28259
28350
|
onProgress ? (bytesHashed) => {
|
|
28260
28351
|
onProgress({ phase: "materializing", fileIndex: fi, fileCount, fileName: file.name, bytesProcessed: bytesHashed, fileTotalBytes: file.size });
|
|
28261
|
-
} : void 0
|
|
28352
|
+
} : void 0,
|
|
28353
|
+
DEFAULT_CHUNK_SIZE,
|
|
28354
|
+
options.signal
|
|
28262
28355
|
);
|
|
28263
28356
|
}
|
|
28264
28357
|
const objectId = (lookupHit == null ? void 0 : lookupHit.objectId) ?? materialized.objectId;
|
|
28265
28358
|
const fileObject = (lookupHit == null ? void 0 : lookupHit.fileObject) ?? materialized.fileObject;
|
|
28266
28359
|
const chunks = lookupHit ? [] : materialized.chunks;
|
|
28360
|
+
if (materialized)
|
|
28361
|
+
for (const object2 of materialized.objects)
|
|
28362
|
+
manifest.set(object2.obj_id, object2);
|
|
28363
|
+
else {
|
|
28364
|
+
const [, objData] = new FileObject(file.name, file.size, fileObject.content).genObjId();
|
|
28365
|
+
manifest.set(objectId, { obj_id: objectId, obj_data: objData });
|
|
28366
|
+
}
|
|
28367
|
+
const qcid = (lookupHit == null ? void 0 : lookupHit.qcid) ?? await tryCalculateQcidFromFile(file);
|
|
28368
|
+
if (qcid)
|
|
28369
|
+
qcidLinks.push({ qcid, content_id: fileObject.content, size: file.size });
|
|
28370
|
+
throwIfCancelled(options.signal);
|
|
28267
28371
|
const imported = {
|
|
28268
28372
|
kind: "file",
|
|
28269
28373
|
objectId,
|
|
@@ -28306,7 +28410,10 @@ async function pickupAndImport(options) {
|
|
|
28306
28410
|
let items;
|
|
28307
28411
|
let selection;
|
|
28308
28412
|
if (options.mode === "single_dir") {
|
|
28309
|
-
|
|
28413
|
+
let index = 0;
|
|
28414
|
+
const rebuild = (node) => ({ kind: "dir", name: node.name, objectId: "", children: node.children.map((child) => child.kind === "file" ? fileObjects[index++] : rebuild(child)) });
|
|
28415
|
+
const dirObj = tree ? rebuild(tree) : buildDirTree(files, fileObjects);
|
|
28416
|
+
computeDirObjectIds(dirObj, manifest);
|
|
28310
28417
|
items = [dirObj];
|
|
28311
28418
|
selection = dirObj;
|
|
28312
28419
|
} else {
|
|
@@ -28319,32 +28426,35 @@ async function pickupAndImport(options) {
|
|
|
28319
28426
|
}
|
|
28320
28427
|
const summary = collectSummary(items);
|
|
28321
28428
|
const sessionId = generateSessionId();
|
|
28322
|
-
|
|
28323
|
-
|
|
28324
|
-
materializationStatus = "all_in_store";
|
|
28325
|
-
} else if (caps.canUseNDMCache) {
|
|
28326
|
-
materializationStatus = "on_cache";
|
|
28327
|
-
}
|
|
28328
|
-
const uploadStatus = materializationStatus === "all_in_store" ? "not_required" : "not_started";
|
|
28429
|
+
const materializationStatus = allFilesAlreadyStored ? "all_in_store" : "ok";
|
|
28430
|
+
const uploadStatus = "not_started";
|
|
28329
28431
|
const session = {
|
|
28330
28432
|
sessionId,
|
|
28331
28433
|
items,
|
|
28332
28434
|
materializationStatus,
|
|
28333
28435
|
uploadStatus,
|
|
28334
28436
|
summary,
|
|
28335
|
-
objectStates
|
|
28437
|
+
objectStates,
|
|
28438
|
+
objectStatus: "pending",
|
|
28439
|
+
warnings,
|
|
28440
|
+
manifest,
|
|
28441
|
+
qcidLinks,
|
|
28442
|
+
requestOptions,
|
|
28443
|
+
transmittedBytes: 0
|
|
28336
28444
|
};
|
|
28337
28445
|
sessionRegistry.set(sessionId, session);
|
|
28338
28446
|
const snapshot = {
|
|
28339
28447
|
sessionId,
|
|
28340
28448
|
selection,
|
|
28341
28449
|
items,
|
|
28450
|
+
objectStatus: "pending",
|
|
28451
|
+
warnings,
|
|
28342
28452
|
materializationStatus,
|
|
28343
28453
|
uploadStatus,
|
|
28344
28454
|
summary
|
|
28345
28455
|
};
|
|
28346
28456
|
if (options.autoStartUpload && uploadStatus === "not_started") {
|
|
28347
|
-
startUpload(sessionId).catch(() => {
|
|
28457
|
+
startUpload(sessionId, { endpoint: options.endpoint, sessionToken: options.sessionToken, fetcher: options.fetcher, headers: options.headers, signal: options.signal }).catch(() => {
|
|
28348
28458
|
});
|
|
28349
28459
|
snapshot.uploadStatus = "uploading";
|
|
28350
28460
|
}
|
|
@@ -28358,21 +28468,27 @@ async function getImportSessionStatus(sessionId) {
|
|
|
28358
28468
|
const perObjectProgress = {};
|
|
28359
28469
|
let uploadedBytes = 0;
|
|
28360
28470
|
let uploadedObjects = 0;
|
|
28361
|
-
|
|
28362
|
-
|
|
28363
|
-
|
|
28364
|
-
|
|
28365
|
-
|
|
28366
|
-
|
|
28367
|
-
|
|
28368
|
-
|
|
28369
|
-
|
|
28370
|
-
|
|
28371
|
-
|
|
28471
|
+
const collect = (items) => {
|
|
28472
|
+
for (const item of items) {
|
|
28473
|
+
if (item.kind === "dir") {
|
|
28474
|
+
collect(item.children ?? []);
|
|
28475
|
+
continue;
|
|
28476
|
+
}
|
|
28477
|
+
const state = session.objectStates.get(item.objectId);
|
|
28478
|
+
perObjectProgress[item.objectId] = { objectId: item.objectId, uploadedBytes: state.uploadedBytes, totalBytes: state.size, state: state.state };
|
|
28479
|
+
uploadedBytes += state.uploadedBytes;
|
|
28480
|
+
if (state.state === "completed")
|
|
28481
|
+
uploadedObjects++;
|
|
28482
|
+
}
|
|
28483
|
+
};
|
|
28484
|
+
collect(session.items);
|
|
28372
28485
|
return {
|
|
28373
28486
|
sessionId,
|
|
28374
28487
|
materializationStatus: session.materializationStatus,
|
|
28375
28488
|
uploadStatus: session.uploadStatus,
|
|
28489
|
+
objectStatus: session.objectStatus,
|
|
28490
|
+
error: session.error,
|
|
28491
|
+
warnings: [...session.warnings],
|
|
28376
28492
|
summary: session.summary,
|
|
28377
28493
|
progress: {
|
|
28378
28494
|
uploadedBytes,
|
|
@@ -28388,6 +28504,10 @@ async function getUploadProgress(sessionId) {
|
|
|
28388
28504
|
const result = {
|
|
28389
28505
|
sessionId,
|
|
28390
28506
|
uploadStatus: status.uploadStatus,
|
|
28507
|
+
objectStatus: status.objectStatus,
|
|
28508
|
+
error: status.error,
|
|
28509
|
+
warnings: status.warnings,
|
|
28510
|
+
transmittedBytes: requireSession(sessionId).transmittedBytes,
|
|
28391
28511
|
totalBytes: status.progress.totalBytes,
|
|
28392
28512
|
uploadedBytes: status.progress.uploadedBytes,
|
|
28393
28513
|
totalObjects: status.progress.totalObjects,
|
|
@@ -28405,13 +28525,13 @@ async function getUploadProgress(sessionId) {
|
|
|
28405
28525
|
}
|
|
28406
28526
|
return result;
|
|
28407
28527
|
}
|
|
28408
|
-
async function uploadChunkViaTus(endpoint, file, chunkInfo, chunkIndex,
|
|
28528
|
+
async function uploadChunkViaTus(endpoint, file, chunkInfo, chunkIndex, fileHash, sessionToken, extraHeaders, onProgress, signal) {
|
|
28409
28529
|
const slice = file.slice(chunkInfo.offset, chunkInfo.offset + chunkInfo.length);
|
|
28410
28530
|
const chunkData = new Uint8Array(await slice.arrayBuffer());
|
|
28411
|
-
const logicalPath =
|
|
28531
|
+
const logicalPath = chunkInfo.chunkId;
|
|
28412
28532
|
let tusModule;
|
|
28413
28533
|
try {
|
|
28414
|
-
tusModule = await import("./tus_client-
|
|
28534
|
+
tusModule = await import("./tus_client-d313689e.mjs");
|
|
28415
28535
|
} catch (error) {
|
|
28416
28536
|
const message = error instanceof Error ? error.message : String(error);
|
|
28417
28537
|
throw new NdmError("UPLOAD_FAILED", `Failed to load tus-js-client: ${message}`);
|
|
@@ -28424,12 +28544,12 @@ async function uploadChunkViaTus(endpoint, file, chunkInfo, chunkIndex, appId, f
|
|
|
28424
28544
|
const blob = new Blob([chunkData]);
|
|
28425
28545
|
const upload = new tusModule.Upload(blob, {
|
|
28426
28546
|
endpoint: `${endpoint}/ndm/v1/uploads`,
|
|
28427
|
-
|
|
28547
|
+
...typeof XMLHttpRequest === "undefined" ? { httpStack: tusModule.fetchHttpStack } : {},
|
|
28548
|
+
headers: { ...extraHeaders, ...sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {} },
|
|
28428
28549
|
chunkSize: chunkData.length,
|
|
28429
28550
|
retryDelays: [0, 1e3, 3e3, 5e3],
|
|
28430
28551
|
storeFingerprintForResuming: false,
|
|
28431
28552
|
metadata: {
|
|
28432
|
-
app_id: appId,
|
|
28433
28553
|
logical_path: logicalPath,
|
|
28434
28554
|
file_name: file.name,
|
|
28435
28555
|
file_size: String(file.size),
|
|
@@ -28443,109 +28563,209 @@ async function uploadChunkViaTus(endpoint, file, chunkInfo, chunkIndex, appId, f
|
|
|
28443
28563
|
},
|
|
28444
28564
|
onSuccess: () => {
|
|
28445
28565
|
onProgress(chunkData.length);
|
|
28566
|
+
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
28446
28567
|
resolve(chunkInfo.chunkId);
|
|
28447
28568
|
},
|
|
28448
28569
|
onError: (error) => {
|
|
28570
|
+
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
28449
28571
|
reject(new NdmError("UPLOAD_FAILED", error.message));
|
|
28450
28572
|
}
|
|
28451
28573
|
});
|
|
28452
|
-
|
|
28453
|
-
|
|
28454
|
-
|
|
28455
|
-
|
|
28456
|
-
|
|
28457
|
-
}
|
|
28574
|
+
const onAbort = () => {
|
|
28575
|
+
void Promise.resolve(upload.abort(true)).catch(() => void 0);
|
|
28576
|
+
reject(new NdmError("USER_CANCELLED", "Upload cancelled"));
|
|
28577
|
+
};
|
|
28578
|
+
signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
|
|
28458
28579
|
upload.start();
|
|
28459
28580
|
});
|
|
28460
28581
|
}
|
|
28461
|
-
|
|
28582
|
+
function errorMessage(error) {
|
|
28583
|
+
return error instanceof Error ? error.message : String(error);
|
|
28584
|
+
}
|
|
28585
|
+
function throwIfCancelled(signal) {
|
|
28586
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
28587
|
+
throw new NdmError("USER_CANCELLED", "Import cancelled");
|
|
28588
|
+
}
|
|
28589
|
+
function requireSession(sessionId) {
|
|
28462
28590
|
const session = sessionRegistry.get(sessionId);
|
|
28463
|
-
if (!session)
|
|
28591
|
+
if (!session)
|
|
28464
28592
|
throw new NdmError("SESSION_NOT_FOUND", `Session ${sessionId} not found`);
|
|
28465
|
-
|
|
28466
|
-
|
|
28467
|
-
|
|
28468
|
-
|
|
28469
|
-
|
|
28470
|
-
|
|
28471
|
-
}
|
|
28472
|
-
if (session.materializationStatus === "all_in_store") {
|
|
28473
|
-
session.uploadStatus = "not_required";
|
|
28593
|
+
return session;
|
|
28594
|
+
}
|
|
28595
|
+
async function startUpload(sessionId, options = {}) {
|
|
28596
|
+
var _a2;
|
|
28597
|
+
const session = requireSession(sessionId);
|
|
28598
|
+
if (session.objectStatus === "ready" || session.uploadPromise)
|
|
28474
28599
|
return getImportSessionStatus(sessionId);
|
|
28475
|
-
|
|
28600
|
+
const concurrency = options.concurrency ?? 3;
|
|
28601
|
+
if (!Number.isInteger(concurrency) || concurrency < 1)
|
|
28602
|
+
throw new NdmError("UPLOAD_FAILED", "concurrency must be a positive integer");
|
|
28603
|
+
throwIfCancelled(options.signal);
|
|
28604
|
+
session.requestOptions = { ...session.requestOptions, ...Object.fromEntries(Object.entries({ endpoint: options.endpoint, sessionToken: options.sessionToken, fetcher: options.fetcher, headers: options.headers }).filter(([, value]) => value !== void 0)) };
|
|
28605
|
+
const endpoint = session.requestOptions.endpoint ?? resolveImportLookupEndpoint();
|
|
28606
|
+
if (!endpoint)
|
|
28607
|
+
throw new NdmError("STORE_API_ENDPOINT_REQUIRED", "Pass endpoint or initialize the SDK before uploading");
|
|
28608
|
+
session.requestOptions.endpoint = normalizeEndpoint$1(endpoint);
|
|
28609
|
+
session.abortController = new AbortController();
|
|
28610
|
+
const cancel = () => {
|
|
28611
|
+
var _a3;
|
|
28612
|
+
return (_a3 = session.abortController) == null ? void 0 : _a3.abort();
|
|
28613
|
+
};
|
|
28614
|
+
(_a2 = options.signal) == null ? void 0 : _a2.addEventListener("abort", cancel, { once: true });
|
|
28615
|
+
session.requestOptions.signal = session.abortController.signal;
|
|
28476
28616
|
session.uploadStatus = "uploading";
|
|
28617
|
+
session.objectStatus = "pending";
|
|
28618
|
+
session.error = void 0;
|
|
28619
|
+
session.onProgress = options.onProgress;
|
|
28477
28620
|
session.uploadStartTime = Date.now();
|
|
28478
|
-
session.
|
|
28479
|
-
|
|
28480
|
-
|
|
28481
|
-
|
|
28482
|
-
|
|
28483
|
-
|
|
28484
|
-
|
|
28485
|
-
}
|
|
28486
|
-
|
|
28487
|
-
|
|
28621
|
+
session.uploadPromise = doUpload(session, concurrency).catch((error) => {
|
|
28622
|
+
var _a3;
|
|
28623
|
+
session.error = errorMessage(error);
|
|
28624
|
+
const cancelled = (_a3 = session.abortController) == null ? void 0 : _a3.signal.aborted;
|
|
28625
|
+
session.uploadStatus = cancelled ? "cancelled" : "failed";
|
|
28626
|
+
session.objectStatus = cancelled ? "cancelled" : "failed";
|
|
28627
|
+
throw error;
|
|
28628
|
+
}).finally(() => {
|
|
28629
|
+
var _a3;
|
|
28630
|
+
session.uploadPromise = void 0;
|
|
28631
|
+
(_a3 = options.signal) == null ? void 0 : _a3.removeEventListener("abort", cancel);
|
|
28632
|
+
emitProgress(session);
|
|
28488
28633
|
});
|
|
28634
|
+
void session.uploadPromise.catch(() => void 0);
|
|
28489
28635
|
return getImportSessionStatus(sessionId);
|
|
28490
28636
|
}
|
|
28491
|
-
async function
|
|
28492
|
-
|
|
28493
|
-
|
|
28494
|
-
|
|
28495
|
-
|
|
28496
|
-
|
|
28497
|
-
|
|
28498
|
-
|
|
28499
|
-
|
|
28500
|
-
|
|
28501
|
-
|
|
28502
|
-
|
|
28503
|
-
|
|
28504
|
-
|
|
28505
|
-
|
|
28506
|
-
|
|
28507
|
-
|
|
28508
|
-
|
|
28509
|
-
|
|
28510
|
-
|
|
28511
|
-
|
|
28512
|
-
|
|
28513
|
-
|
|
28514
|
-
|
|
28515
|
-
|
|
28516
|
-
|
|
28517
|
-
|
|
28518
|
-
}
|
|
28519
|
-
});
|
|
28520
|
-
}
|
|
28637
|
+
async function ensureUploaded(sessionId, options = {}) {
|
|
28638
|
+
await startUpload(sessionId, options);
|
|
28639
|
+
const session = requireSession(sessionId);
|
|
28640
|
+
await session.uploadPromise;
|
|
28641
|
+
if (session.objectStatus !== "ready")
|
|
28642
|
+
throw new NdmError("OBJECT_NOT_READY", session.error ?? "Objects are not ready");
|
|
28643
|
+
return getImportSessionStatus(sessionId);
|
|
28644
|
+
}
|
|
28645
|
+
function cancelImportSession(sessionId) {
|
|
28646
|
+
var _a2;
|
|
28647
|
+
const session = requireSession(sessionId);
|
|
28648
|
+
if (session.objectStatus === "ready")
|
|
28649
|
+
return;
|
|
28650
|
+
(_a2 = session.abortController) == null ? void 0 : _a2.abort();
|
|
28651
|
+
session.uploadStatus = "cancelled";
|
|
28652
|
+
session.objectStatus = "cancelled";
|
|
28653
|
+
}
|
|
28654
|
+
function releaseImportSession(sessionId) {
|
|
28655
|
+
const session = requireSession(sessionId);
|
|
28656
|
+
cancelImportSession(sessionId);
|
|
28657
|
+
sessionRegistry.delete(sessionId);
|
|
28658
|
+
const release = (items) => items.forEach((item) => {
|
|
28659
|
+
if (item.kind === "dir")
|
|
28660
|
+
release(item.children ?? []);
|
|
28661
|
+
else {
|
|
28662
|
+
delete item._file;
|
|
28663
|
+
delete item._ndnFileObject;
|
|
28521
28664
|
}
|
|
28522
|
-
next();
|
|
28523
28665
|
});
|
|
28666
|
+
release(session.items);
|
|
28524
28667
|
}
|
|
28525
|
-
|
|
28526
|
-
|
|
28527
|
-
|
|
28528
|
-
|
|
28529
|
-
|
|
28530
|
-
|
|
28531
|
-
await uploadChunkViaTus(
|
|
28532
|
-
endpoint,
|
|
28533
|
-
state.file,
|
|
28534
|
-
chunk,
|
|
28535
|
-
chunkIndex,
|
|
28536
|
-
"default",
|
|
28537
|
-
state.objectId,
|
|
28538
|
-
await sessionToken(),
|
|
28539
|
-
(uploaded) => {
|
|
28540
|
-
const prevChunkBytes = state.chunks.filter((c) => c !== chunk && c.uploaded).reduce((sum, c) => sum + c.length, 0);
|
|
28541
|
-
state.uploadedBytes = prevChunkBytes + uploaded;
|
|
28542
|
-
},
|
|
28543
|
-
(_a2 = session.abortController) == null ? void 0 : _a2.signal
|
|
28544
|
-
);
|
|
28545
|
-
chunk.uploaded = true;
|
|
28668
|
+
function emitProgress(session) {
|
|
28669
|
+
if (session.onProgress && sessionRegistry.has(session.sessionId)) {
|
|
28670
|
+
void getUploadProgress(session.sessionId).then((progress) => {
|
|
28671
|
+
var _a2;
|
|
28672
|
+
return (_a2 = session.onProgress) == null ? void 0 : _a2.call(session, progress);
|
|
28673
|
+
}).catch(() => void 0);
|
|
28546
28674
|
}
|
|
28547
|
-
|
|
28548
|
-
|
|
28675
|
+
}
|
|
28676
|
+
async function doUpload(session, concurrency) {
|
|
28677
|
+
var _a2;
|
|
28678
|
+
const states = [...session.objectStates.values()];
|
|
28679
|
+
const chunkTasks = /* @__PURE__ */ new Map();
|
|
28680
|
+
let index = 0;
|
|
28681
|
+
let failure;
|
|
28682
|
+
const workers = Array.from({ length: Math.min(concurrency, states.length) }, async () => {
|
|
28683
|
+
var _a3, _b;
|
|
28684
|
+
while (index < states.length && !failure) {
|
|
28685
|
+
const state = states[index++];
|
|
28686
|
+
try {
|
|
28687
|
+
throwIfCancelled((_a3 = session.abortController) == null ? void 0 : _a3.signal);
|
|
28688
|
+
if (state.state === "completed")
|
|
28689
|
+
continue;
|
|
28690
|
+
state.state = "uploading";
|
|
28691
|
+
for (const [chunkIndex, chunk] of state.chunks.entries()) {
|
|
28692
|
+
throwIfCancelled((_b = session.abortController) == null ? void 0 : _b.signal);
|
|
28693
|
+
if (chunk.uploaded)
|
|
28694
|
+
continue;
|
|
28695
|
+
let task = chunkTasks.get(chunk.chunkId);
|
|
28696
|
+
if (!task) {
|
|
28697
|
+
task = uploadMissingChunk(session, state, chunk, chunkIndex);
|
|
28698
|
+
chunkTasks.set(chunk.chunkId, task);
|
|
28699
|
+
}
|
|
28700
|
+
await task;
|
|
28701
|
+
chunk.uploaded = true;
|
|
28702
|
+
state.uploadedBytes = state.chunks.filter((c) => c.uploaded).reduce((sum, c) => sum + c.length, 0);
|
|
28703
|
+
emitProgress(session);
|
|
28704
|
+
}
|
|
28705
|
+
state.uploadedBytes = state.size;
|
|
28706
|
+
state.state = "completed";
|
|
28707
|
+
} catch (error) {
|
|
28708
|
+
state.state = "failed";
|
|
28709
|
+
failure = error;
|
|
28710
|
+
}
|
|
28711
|
+
}
|
|
28712
|
+
});
|
|
28713
|
+
await Promise.all(workers);
|
|
28714
|
+
if (failure)
|
|
28715
|
+
throw failure;
|
|
28716
|
+
throwIfCancelled((_a2 = session.abortController) == null ? void 0 : _a2.signal);
|
|
28717
|
+
session.objectStatus = "finalizing";
|
|
28718
|
+
emitProgress(session);
|
|
28719
|
+
const options = session.requestOptions;
|
|
28720
|
+
const token = options.sessionToken !== void 0 ? options.sessionToken : await getActiveSessionToken();
|
|
28721
|
+
const response = await (options.fetcher ?? defaultStoreFetcher)(`${options.endpoint}/ndm/v1/import/finalize`, {
|
|
28722
|
+
method: "POST",
|
|
28723
|
+
credentials: "include",
|
|
28724
|
+
signal: options.signal,
|
|
28725
|
+
headers: { ...options.headers, "Content-Type": "application/json", ...token ? { Authorization: `Bearer ${token}` } : {} },
|
|
28726
|
+
body: JSON.stringify({ objects: [...session.manifest.values()], roots: session.items.map((item) => item.objectId), qcid_links: session.qcidLinks })
|
|
28727
|
+
});
|
|
28728
|
+
const body = await response.json();
|
|
28729
|
+
if (!response.ok)
|
|
28730
|
+
throw new NdmStoreApiError(response.status, body.error, body.message ?? "Object registration failed", body);
|
|
28731
|
+
throwIfCancelled(options.signal);
|
|
28732
|
+
if (Array.isArray(body.warnings))
|
|
28733
|
+
session.warnings.push(...body.warnings.map(String));
|
|
28734
|
+
if (body.ready !== true || !Array.isArray(body.roots) || session.items.some((item) => !body.roots.some((root) => root.obj_id === item.objectId && root.ready === true))) {
|
|
28735
|
+
throw new NdmError("OBJECT_NOT_READY", "NDM did not confirm all root objects and their dependencies are ready");
|
|
28736
|
+
}
|
|
28737
|
+
session.objectStatus = "ready";
|
|
28738
|
+
session.uploadStatus = session.transmittedBytes === 0 ? "not_required" : "completed";
|
|
28739
|
+
session.materializationStatus = "all_in_store";
|
|
28740
|
+
emitProgress(session);
|
|
28741
|
+
}
|
|
28742
|
+
async function uploadMissingChunk(session, state, chunk, chunkIndex) {
|
|
28743
|
+
var _a2, _b;
|
|
28744
|
+
try {
|
|
28745
|
+
const found = await lookupObject({ scope: "app", quick_hash: chunk.chunkId }, session.requestOptions);
|
|
28746
|
+
if (found.reusable === true && "state" in found && ["completed", "same_as", "local_link"].includes(found.state) && found.chunk_size === chunk.length)
|
|
28747
|
+
return;
|
|
28748
|
+
} catch (error) {
|
|
28749
|
+
throwIfCancelled((_a2 = session.abortController) == null ? void 0 : _a2.signal);
|
|
28750
|
+
if (!(error instanceof NdmStoreApiError && error.status === 404))
|
|
28751
|
+
session.warnings.push(`Chunk lookup: ${errorMessage(error)}`);
|
|
28752
|
+
}
|
|
28753
|
+
const token = session.requestOptions.sessionToken !== void 0 ? session.requestOptions.sessionToken : await getActiveSessionToken();
|
|
28754
|
+
await uploadChunkViaTus(
|
|
28755
|
+
session.requestOptions.endpoint,
|
|
28756
|
+
state.file,
|
|
28757
|
+
chunk,
|
|
28758
|
+
chunkIndex,
|
|
28759
|
+
state.objectId,
|
|
28760
|
+
token,
|
|
28761
|
+
session.requestOptions.headers,
|
|
28762
|
+
(uploaded) => {
|
|
28763
|
+
state.uploadedBytes = state.chunks.filter((c) => c.uploaded).reduce((sum, c) => sum + c.length, 0) + uploaded;
|
|
28764
|
+
emitProgress(session);
|
|
28765
|
+
},
|
|
28766
|
+
(_b = session.abortController) == null ? void 0 : _b.signal
|
|
28767
|
+
);
|
|
28768
|
+
session.transmittedBytes += chunk.length;
|
|
28549
28769
|
}
|
|
28550
28770
|
const ndm_client = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
28551
28771
|
__proto__: null,
|
|
@@ -28555,7 +28775,9 @@ const ndm_client = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
28555
28775
|
anchorState: anchorState$1,
|
|
28556
28776
|
applyEdge: applyEdge$1,
|
|
28557
28777
|
calculateQcidFromFile,
|
|
28778
|
+
cancelImportSession,
|
|
28558
28779
|
debugDumpExpandState: debugDumpExpandState$1,
|
|
28780
|
+
ensureUploaded,
|
|
28559
28781
|
forcedGcUntil: forcedGcUntil$1,
|
|
28560
28782
|
fsAcquire: fsAcquire$1,
|
|
28561
28783
|
fsAnchorState: fsAnchorState$1,
|
|
@@ -28567,6 +28789,8 @@ const ndm_client = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
28567
28789
|
getObject: getObject$1,
|
|
28568
28790
|
getUploadProgress,
|
|
28569
28791
|
haveChunk: haveChunk$1,
|
|
28792
|
+
importDirectory,
|
|
28793
|
+
importFiles,
|
|
28570
28794
|
isObjectExist: isObjectExist$1,
|
|
28571
28795
|
isObjectStored: isObjectStored$1,
|
|
28572
28796
|
lookupObject,
|
|
@@ -28577,6 +28801,7 @@ const ndm_client = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
28577
28801
|
putObject: putObject$1,
|
|
28578
28802
|
queryChunkState: queryChunkState$1,
|
|
28579
28803
|
queryObjectById: queryObjectById$1,
|
|
28804
|
+
releaseImportSession,
|
|
28580
28805
|
removeChunk: removeChunk$1,
|
|
28581
28806
|
removeObject: removeObject$1,
|
|
28582
28807
|
setImportProvider,
|
|
@@ -29134,6 +29359,279 @@ const ndm_proxy = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
|
|
|
29134
29359
|
unpin,
|
|
29135
29360
|
unpinOwner
|
|
29136
29361
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
29362
|
+
class ExecutorClient {
|
|
29363
|
+
constructor(serviceUrl, token = null, options = {}) {
|
|
29364
|
+
this.rpc = new kRPCClient(serviceUrl, token, null, options);
|
|
29365
|
+
}
|
|
29366
|
+
syncSessionToken(token) {
|
|
29367
|
+
this.rpc.setSessionToken(token);
|
|
29368
|
+
}
|
|
29369
|
+
createDevice(input) {
|
|
29370
|
+
return this.rpc.call("executor.device.create", input);
|
|
29371
|
+
}
|
|
29372
|
+
listDevices() {
|
|
29373
|
+
return this.rpc.call("executor.device.list", {});
|
|
29374
|
+
}
|
|
29375
|
+
issueAccess(executor_id, expires_at_ms) {
|
|
29376
|
+
return this.rpc.call("executor.device.issue", { executor_id, expires_at_ms });
|
|
29377
|
+
}
|
|
29378
|
+
revokeAccess(executor_id) {
|
|
29379
|
+
return this.rpc.call("executor.device.revoke", { executor_id });
|
|
29380
|
+
}
|
|
29381
|
+
deleteDevice(executor_id) {
|
|
29382
|
+
return this.rpc.call("executor.device.delete", { executor_id });
|
|
29383
|
+
}
|
|
29384
|
+
listOnline() {
|
|
29385
|
+
return this.rpc.call("executor.online.list", {});
|
|
29386
|
+
}
|
|
29387
|
+
async *watchOnline(signal, intervalMs = 5e3) {
|
|
29388
|
+
if (intervalMs < 250)
|
|
29389
|
+
throw new Error("Watch interval must be at least 250 ms");
|
|
29390
|
+
let previous = "";
|
|
29391
|
+
while (!(signal == null ? void 0 : signal.aborted)) {
|
|
29392
|
+
const { executors } = await this.listOnline();
|
|
29393
|
+
const next = JSON.stringify(executors);
|
|
29394
|
+
if (next !== previous) {
|
|
29395
|
+
previous = next;
|
|
29396
|
+
yield executors;
|
|
29397
|
+
}
|
|
29398
|
+
await new Promise((resolve) => {
|
|
29399
|
+
const done = () => {
|
|
29400
|
+
clearTimeout(timer);
|
|
29401
|
+
signal == null ? void 0 : signal.removeEventListener("abort", done);
|
|
29402
|
+
resolve();
|
|
29403
|
+
};
|
|
29404
|
+
const timer = setTimeout(done, intervalMs);
|
|
29405
|
+
signal == null ? void 0 : signal.addEventListener("abort", done, { once: true });
|
|
29406
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
29407
|
+
done();
|
|
29408
|
+
});
|
|
29409
|
+
}
|
|
29410
|
+
}
|
|
29411
|
+
openRoute(target) {
|
|
29412
|
+
return this.rpc.call("executor.stream.open", {
|
|
29413
|
+
executor_id: target.executor_id,
|
|
29414
|
+
generation: target.generation,
|
|
29415
|
+
profile_id: target.profile_id
|
|
29416
|
+
});
|
|
29417
|
+
}
|
|
29418
|
+
async connect(target, sessionToken, runtimeId, runId) {
|
|
29419
|
+
const route = await this.openRoute(target);
|
|
29420
|
+
return ExecutorCommandStream.connect(route, target, sessionToken, runtimeId, runId);
|
|
29421
|
+
}
|
|
29422
|
+
}
|
|
29423
|
+
class ExecutorStreamError extends Error {
|
|
29424
|
+
constructor(message, code = "unavailable", effectUnknown = false) {
|
|
29425
|
+
super(message);
|
|
29426
|
+
this.code = code;
|
|
29427
|
+
this.effectUnknown = effectUnknown;
|
|
29428
|
+
this.name = "ExecutorStreamError";
|
|
29429
|
+
}
|
|
29430
|
+
}
|
|
29431
|
+
function encodeExecutorControl(message) {
|
|
29432
|
+
const payload = new TextEncoder().encode(JSON.stringify(message));
|
|
29433
|
+
if (payload.length > 1024 * 1024)
|
|
29434
|
+
throw new Error("Executor control frame exceeds 1 MiB");
|
|
29435
|
+
const frame = new Uint8Array(5 + payload.length);
|
|
29436
|
+
frame[0] = 1;
|
|
29437
|
+
new DataView(frame.buffer).setUint32(1, payload.length);
|
|
29438
|
+
frame.set(payload, 5);
|
|
29439
|
+
return frame;
|
|
29440
|
+
}
|
|
29441
|
+
class ExecutorCommandStream {
|
|
29442
|
+
constructor(socket, target, runId) {
|
|
29443
|
+
this.socket = socket;
|
|
29444
|
+
this.target = target;
|
|
29445
|
+
this.runId = runId;
|
|
29446
|
+
this.buffer = new Uint8Array();
|
|
29447
|
+
this.sequence = 0;
|
|
29448
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
29449
|
+
this.closed = false;
|
|
29450
|
+
socket.binaryType = "arraybuffer";
|
|
29451
|
+
socket.onmessage = (event) => {
|
|
29452
|
+
if (!(event.data instanceof ArrayBuffer)) {
|
|
29453
|
+
this.fail(new ExecutorStreamError("Expected binary Command Stream"));
|
|
29454
|
+
return;
|
|
29455
|
+
}
|
|
29456
|
+
try {
|
|
29457
|
+
this.receive(new Uint8Array(event.data));
|
|
29458
|
+
} catch {
|
|
29459
|
+
this.fail(new ExecutorStreamError("Invalid Command Stream frame", "protocol"));
|
|
29460
|
+
}
|
|
29461
|
+
};
|
|
29462
|
+
socket.onclose = () => this.fail(new ExecutorStreamError("Executor disconnected; query the persisted operation locator before taking further action", "unavailable", true));
|
|
29463
|
+
socket.onerror = () => this.fail(new ExecutorStreamError("Executor transport failed", "unavailable", true));
|
|
29464
|
+
}
|
|
29465
|
+
static async connect(route, target, token, runtimeId, runId) {
|
|
29466
|
+
if (route.executor_id !== target.executor_id || route.generation !== target.generation || route.profile_id !== target.profile_id || route.expires_at_ms <= Date.now()) {
|
|
29467
|
+
throw new ExecutorStreamError("Route does not match the requested active executor", "stale_target");
|
|
29468
|
+
}
|
|
29469
|
+
const url = new URL(route.ws_url);
|
|
29470
|
+
if (url.protocol !== "wss:" && !(url.protocol === "ws:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) {
|
|
29471
|
+
throw new ExecutorStreamError("Executor routes require WSS");
|
|
29472
|
+
}
|
|
29473
|
+
if (url.username || url.password || url.hash)
|
|
29474
|
+
throw new ExecutorStreamError("Invalid executor route URL");
|
|
29475
|
+
const socket = new WebSocket(url);
|
|
29476
|
+
await new Promise((resolve, reject) => {
|
|
29477
|
+
const timer = setTimeout(() => {
|
|
29478
|
+
socket.close();
|
|
29479
|
+
reject(new ExecutorStreamError("Route authentication timed out"));
|
|
29480
|
+
}, 1e4);
|
|
29481
|
+
socket.onopen = () => socket.send(JSON.stringify({ ticket: route.ticket }));
|
|
29482
|
+
socket.onmessage = (event) => {
|
|
29483
|
+
try {
|
|
29484
|
+
if (typeof event.data !== "string" || JSON.parse(event.data).ready !== true)
|
|
29485
|
+
throw new Error();
|
|
29486
|
+
clearTimeout(timer);
|
|
29487
|
+
resolve();
|
|
29488
|
+
} catch {
|
|
29489
|
+
clearTimeout(timer);
|
|
29490
|
+
socket.close();
|
|
29491
|
+
reject(new ExecutorStreamError("Route authentication failed"));
|
|
29492
|
+
}
|
|
29493
|
+
};
|
|
29494
|
+
socket.onerror = socket.onclose = () => {
|
|
29495
|
+
clearTimeout(timer);
|
|
29496
|
+
reject(new ExecutorStreamError("Unable to connect executor route"));
|
|
29497
|
+
};
|
|
29498
|
+
});
|
|
29499
|
+
const client = new ExecutorCommandStream(socket, target, runId);
|
|
29500
|
+
try {
|
|
29501
|
+
const login = await client.request("login", { v: 1, token, profile: target.profile_id, client: { runtime_id: runtimeId, run_id: runId } });
|
|
29502
|
+
if (login.type !== "login_ok" || login.store_id !== target.store_id)
|
|
29503
|
+
throw new ExecutorStreamError("Executor ledger changed", "store_mismatch");
|
|
29504
|
+
return client;
|
|
29505
|
+
} catch (error) {
|
|
29506
|
+
client.close();
|
|
29507
|
+
throw error;
|
|
29508
|
+
}
|
|
29509
|
+
}
|
|
29510
|
+
receive(bytes2) {
|
|
29511
|
+
const merged = new Uint8Array(this.buffer.length + bytes2.length);
|
|
29512
|
+
merged.set(this.buffer);
|
|
29513
|
+
merged.set(bytes2, this.buffer.length);
|
|
29514
|
+
this.buffer = merged;
|
|
29515
|
+
while (this.buffer.length >= 5) {
|
|
29516
|
+
const length = new DataView(this.buffer.buffer, this.buffer.byteOffset).getUint32(1);
|
|
29517
|
+
if (length > 1024 * 1024 || ![1, 2].includes(this.buffer[0]))
|
|
29518
|
+
throw new Error();
|
|
29519
|
+
if (this.buffer.length < length + 5)
|
|
29520
|
+
return;
|
|
29521
|
+
const kind = this.buffer[0];
|
|
29522
|
+
const payload = this.buffer.slice(5, length + 5);
|
|
29523
|
+
this.buffer = this.buffer.slice(length + 5);
|
|
29524
|
+
if (kind !== 1)
|
|
29525
|
+
continue;
|
|
29526
|
+
const reply = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(payload));
|
|
29527
|
+
if (reply.type === "closing") {
|
|
29528
|
+
this.fail(new ExecutorStreamError("Executor stopped accepting requests"));
|
|
29529
|
+
return;
|
|
29530
|
+
}
|
|
29531
|
+
const pending = reply.request_id && this.pending.get(reply.request_id);
|
|
29532
|
+
if (!pending)
|
|
29533
|
+
continue;
|
|
29534
|
+
this.pending.delete(reply.request_id);
|
|
29535
|
+
clearTimeout(pending.timer);
|
|
29536
|
+
if (reply.error)
|
|
29537
|
+
pending.reject(new ExecutorStreamError(reply.error.message, reply.error.code, reply.error.effect_unknown));
|
|
29538
|
+
else
|
|
29539
|
+
pending.resolve(reply);
|
|
29540
|
+
}
|
|
29541
|
+
}
|
|
29542
|
+
fail(error) {
|
|
29543
|
+
if (this.closed)
|
|
29544
|
+
return;
|
|
29545
|
+
this.closed = true;
|
|
29546
|
+
for (const item of this.pending.values()) {
|
|
29547
|
+
clearTimeout(item.timer);
|
|
29548
|
+
item.reject(error);
|
|
29549
|
+
}
|
|
29550
|
+
this.pending.clear();
|
|
29551
|
+
this.socket.close();
|
|
29552
|
+
}
|
|
29553
|
+
close() {
|
|
29554
|
+
this.fail(new ExecutorStreamError("Executor stream closed", "unavailable", true));
|
|
29555
|
+
}
|
|
29556
|
+
request(type, params = {}, timeoutMs = 4e4) {
|
|
29557
|
+
if (this.closed)
|
|
29558
|
+
return Promise.reject(new ExecutorStreamError("Executor stream is closed"));
|
|
29559
|
+
const request_id = `q${++this.sequence}`;
|
|
29560
|
+
return new Promise((resolve, reject) => {
|
|
29561
|
+
const timer = setTimeout(() => {
|
|
29562
|
+
this.pending.delete(request_id);
|
|
29563
|
+
reject(new ExecutorStreamError("Executor response timed out; query operation before retrying", "unavailable", true));
|
|
29564
|
+
}, timeoutMs);
|
|
29565
|
+
this.pending.set(request_id, { resolve, reject, timer });
|
|
29566
|
+
try {
|
|
29567
|
+
this.socket.send(encodeExecutorControl({ ...params, type, request_id }));
|
|
29568
|
+
} catch {
|
|
29569
|
+
clearTimeout(timer);
|
|
29570
|
+
this.pending.delete(request_id);
|
|
29571
|
+
reject(new ExecutorStreamError("Unable to send request", "unavailable", true));
|
|
29572
|
+
}
|
|
29573
|
+
});
|
|
29574
|
+
}
|
|
29575
|
+
operation(locator) {
|
|
29576
|
+
if (locator.executor_id !== this.target.executor_id || locator.store_id !== this.target.store_id || locator.profile_id !== this.target.profile_id) {
|
|
29577
|
+
throw new ExecutorStreamError("Operation locator belongs to another executor, profile or ledger", "store_mismatch");
|
|
29578
|
+
}
|
|
29579
|
+
return { store_id: locator.store_id, op_id: locator.op_id, run_id: locator.run_id, call_id: locator.call_id };
|
|
29580
|
+
}
|
|
29581
|
+
fresh(locator) {
|
|
29582
|
+
if (locator.generation !== this.target.generation)
|
|
29583
|
+
throw new ExecutorStreamError("Cannot dispatch an old operation to a new connection generation", "stale_target");
|
|
29584
|
+
return this.operation(locator);
|
|
29585
|
+
}
|
|
29586
|
+
async describe(workdir) {
|
|
29587
|
+
const reply = await this.request("describe", { workdir });
|
|
29588
|
+
const described = reply.target;
|
|
29589
|
+
if (reply.type !== "describe_ok" || (described == null ? void 0 : described.executor_id) !== this.target.executor_id || (described == null ? void 0 : described.node_did) || (described == null ? void 0 : described.profile_id) !== this.target.profile_id || (described == null ? void 0 : described.store_id) !== this.target.store_id) {
|
|
29590
|
+
throw new ExecutorStreamError("Executor describe target changed", "stale_target");
|
|
29591
|
+
}
|
|
29592
|
+
return reply;
|
|
29593
|
+
}
|
|
29594
|
+
exec(locator, cmd, cwd, env_overrides = {}, execution_timeout_ms = 6e4) {
|
|
29595
|
+
return this.request("exec", { ...this.fresh(locator), cmd, cwd, env_overrides, execution_timeout_ms });
|
|
29596
|
+
}
|
|
29597
|
+
read(locator, path) {
|
|
29598
|
+
return this.request("read", { ...this.fresh(locator), path, offset: 0 });
|
|
29599
|
+
}
|
|
29600
|
+
edit(locator, path, edits) {
|
|
29601
|
+
return this.request("edit", { ...this.fresh(locator), path, edits });
|
|
29602
|
+
}
|
|
29603
|
+
async write(locator, path, content, mode = "replace") {
|
|
29604
|
+
const operation = this.fresh(locator);
|
|
29605
|
+
const id2 = new TextEncoder().encode(locator.op_id);
|
|
29606
|
+
if (id2.length === 0 || id2.length > 128)
|
|
29607
|
+
throw new Error("Invalid operation ID");
|
|
29608
|
+
const hash2 = Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", content))).map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
29609
|
+
const accepted = this.request("write", { ...operation, path, mode, content_length: content.length, content_hash: `sha256:${hash2}` });
|
|
29610
|
+
for (let offset = 0; offset < content.length; offset += 16384) {
|
|
29611
|
+
const chunk = content.subarray(offset, offset + 16384);
|
|
29612
|
+
const frame = new Uint8Array(16 + id2.length + chunk.length);
|
|
29613
|
+
const view = new DataView(frame.buffer);
|
|
29614
|
+
frame[0] = 2;
|
|
29615
|
+
view.setUint32(1, frame.length - 5);
|
|
29616
|
+
frame[5] = 4;
|
|
29617
|
+
view.setBigUint64(6, BigInt(offset));
|
|
29618
|
+
view.setUint16(14, id2.length);
|
|
29619
|
+
frame.set(id2, 16);
|
|
29620
|
+
frame.set(chunk, 16 + id2.length);
|
|
29621
|
+
this.socket.send(frame);
|
|
29622
|
+
}
|
|
29623
|
+
this.socket.send(encodeExecutorControl({ type: "upload_end", request_id: `end${++this.sequence}`, op_id: locator.op_id }));
|
|
29624
|
+
return accepted;
|
|
29625
|
+
}
|
|
29626
|
+
query(locator, channel, offset = 0, wait_ms = 0) {
|
|
29627
|
+
this.operation(locator);
|
|
29628
|
+
return this.request("query", { store_id: locator.store_id, op_id: locator.op_id, channel, offset, max_bytes: 262144, wait_ms });
|
|
29629
|
+
}
|
|
29630
|
+
cancel(locator) {
|
|
29631
|
+
this.operation(locator);
|
|
29632
|
+
return this.request("cancel", { store_id: locator.store_id, op_id: locator.op_id });
|
|
29633
|
+
}
|
|
29634
|
+
}
|
|
29137
29635
|
export {
|
|
29138
29636
|
CONTACT_TAG_HOMESTATION_FOLLOWING as $,
|
|
29139
29637
|
NOTIFY_ACTION_DISMISS as A,
|
|
@@ -29302,6 +29800,13 @@ export {
|
|
|
29302
29800
|
BnsTxExecutorError as c5,
|
|
29303
29801
|
walletUserHasSnAccount as c6,
|
|
29304
29802
|
BnsTxExecutor as c7,
|
|
29803
|
+
ExecutorClient as c8,
|
|
29804
|
+
ExecutorStreamError as c9,
|
|
29805
|
+
encodeExecutorControl as ca,
|
|
29806
|
+
ExecutorCommandStream as cb,
|
|
29807
|
+
AIWORKSPACE_SERVICE_NAME as cc,
|
|
29808
|
+
AiwsFailure as cd,
|
|
29809
|
+
AiWorkspaceClient as ce,
|
|
29305
29810
|
BS_SERVICE_TASK_MANAGER as d,
|
|
29306
29811
|
getActiveRuntimeType as e,
|
|
29307
29812
|
getActiveZoneGatewayOrigin as f,
|
|
@@ -29326,4 +29831,4 @@ export {
|
|
|
29326
29831
|
NOTIFY_TEXT_CONTROL_ID as y,
|
|
29327
29832
|
NOTIFY_ACTION_ANSWER as z
|
|
29328
29833
|
};
|
|
29329
|
-
//# sourceMappingURL=
|
|
29834
|
+
//# sourceMappingURL=executor_client-eb372968.mjs.map
|