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.
Files changed (91) hide show
  1. package/cli/core/app.ts +4 -0
  2. package/cli/core/auth.ts +2 -3
  3. package/cli/dist/cli.mjs +547 -127
  4. package/cli/dist/cli.mjs.map +1 -1
  5. package/cli/modules/aiws.ts +294 -0
  6. package/cli/modules/executor.ts +98 -0
  7. package/cli/version.ts +1 -1
  8. package/dist/account.d.ts +0 -2
  9. package/dist/account.d.ts.map +1 -1
  10. package/dist/aiworkspace_client.d.ts +91 -0
  11. package/dist/aiworkspace_client.d.ts.map +1 -0
  12. package/dist/app-frame.cjs +1 -1
  13. package/dist/app-frame.cjs.map +1 -1
  14. package/dist/app-frame.d.ts +103 -3
  15. package/dist/app-frame.d.ts.map +1 -1
  16. package/dist/app-frame.mjs +189 -8
  17. package/dist/app-frame.mjs.map +1 -1
  18. package/dist/browser.cjs +1 -1
  19. package/dist/browser.cjs.map +1 -1
  20. package/dist/browser.d.ts +2 -0
  21. package/dist/browser.d.ts.map +1 -1
  22. package/dist/browser.mjs +18 -15
  23. package/dist/browser.mjs.map +1 -1
  24. package/dist/content.cjs +1 -1
  25. package/dist/content.cjs.map +1 -1
  26. package/dist/content.d.ts +18 -0
  27. package/dist/content.d.ts.map +1 -1
  28. package/dist/content.mjs +61 -1
  29. package/dist/content.mjs.map +1 -1
  30. package/dist/executor_client-b3ff97ba.js +13 -0
  31. package/dist/executor_client-b3ff97ba.js.map +1 -0
  32. package/dist/{ndm_proxy-6b03b9ec.mjs → executor_client-eb372968.mjs} +901 -396
  33. package/dist/executor_client-eb372968.mjs.map +1 -0
  34. package/dist/executor_client.d.ts +138 -0
  35. package/dist/executor_client.d.ts.map +1 -0
  36. package/dist/index.cjs +1 -1
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.ts +4 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.mjs +23 -15
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/internal/hash_worker.d.ts +2 -1
  43. package/dist/internal/hash_worker.d.ts.map +1 -1
  44. package/dist/internal/tus_client.d.ts +3 -0
  45. package/dist/internal/tus_client.d.ts.map +1 -1
  46. package/dist/namelib.d.ts +1 -10
  47. package/dist/namelib.d.ts.map +1 -1
  48. package/dist/ndm_client.d.ts +56 -7
  49. package/dist/ndm_client.d.ts.map +1 -1
  50. package/dist/ndn_types-08dc9ef1.js +2 -0
  51. package/dist/ndn_types-08dc9ef1.js.map +1 -0
  52. package/dist/{ndn_types-ac9c1e48.mjs → ndn_types-bbb1f6a6.mjs} +53 -100
  53. package/dist/ndn_types-bbb1f6a6.mjs.map +1 -0
  54. package/dist/nfsp.cjs +1 -1
  55. package/dist/nfsp.cjs.map +1 -1
  56. package/dist/nfsp.d.ts +16 -0
  57. package/dist/nfsp.d.ts.map +1 -1
  58. package/dist/nfsp.mjs +6 -0
  59. package/dist/nfsp.mjs.map +1 -1
  60. package/dist/node.cjs +1 -1
  61. package/dist/node.cjs.map +1 -1
  62. package/dist/node.d.ts +2 -0
  63. package/dist/node.d.ts.map +1 -1
  64. package/dist/node.mjs +18 -15
  65. package/dist/node.mjs.map +1 -1
  66. package/dist/provision.cjs +2 -2
  67. package/dist/provision.cjs.map +1 -1
  68. package/dist/provision.mjs +18 -12
  69. package/dist/provision.mjs.map +1 -1
  70. package/dist/provision_activate.d.ts.map +1 -1
  71. package/dist/runtime.d.ts +3 -4
  72. package/dist/runtime.d.ts.map +1 -1
  73. package/dist/sdk_core.d.ts +4 -0
  74. package/dist/sdk_core.d.ts.map +1 -1
  75. package/dist/{tus_client-2b915a81.js → tus_client-65c5fc5e.js} +4 -4
  76. package/dist/tus_client-65c5fc5e.js.map +1 -0
  77. package/dist/{tus_client-19baa342.mjs → tus_client-d313689e.mjs} +40 -2
  78. package/dist/tus_client-d313689e.mjs.map +1 -0
  79. package/dist/types.d.ts +0 -9
  80. package/dist/types.d.ts.map +1 -1
  81. package/dist/verify-hub-client.d.ts +1 -9
  82. package/dist/verify-hub-client.d.ts.map +1 -1
  83. package/package.json +1 -1
  84. package/dist/ndm_proxy-67651066.js +0 -13
  85. package/dist/ndm_proxy-67651066.js.map +0 -1
  86. package/dist/ndm_proxy-6b03b9ec.mjs.map +0 -1
  87. package/dist/ndn_types-324121ae.js +0 -2
  88. package/dist/ndn_types-324121ae.js.map +0 -1
  89. package/dist/ndn_types-ac9c1e48.mjs.map +0 -1
  90. package/dist/tus_client-19baa342.mjs.map +0 -1
  91. 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 { v as DID, w as getBrowserIdentityRaw, x as clearBrowserUserInfo, y as saveBrowserIdentity, z as saveBrowserUserInfo, A as getBrowserUserInfo, B as clearBrowserIdentity, q as parseBuckyOSOwnerDocument, h as hashPassword, C as saveLocalAccountInfo, E as cleanLocalAccountInfo, F as canonicalize, G as signJwtEdDSA, O as ObjId, H as ChunkId, I as FileObject, J as sha256Bytes, K as DirObject, S as SimpleChunkList } from "./ndn_types-ac9c1e48.mjs";
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 deviceName = await this.readDeviceNameFromNodeIdentityPath(path.join(etcDir, "node_identity.json"));
3847
- if (!deviceName) {
3848
- throw new Error(`failed to resolve userid from ${path.join(etcDir, "node_identity.json")} device_mini_doc_jwt`);
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 keyPem = await this.readPemFile(path.join(etcDir, "node_private_key.pem"));
3851
- if (!keyPem) {
3852
- throw new Error(`failed to load node_private_key.pem from ${etcDir}`);
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 raw = await fs.readFile(nodeIdentityPath, "utf8");
3921
- const parsed = JSON.parse(raw);
3922
- const deviceName = this.extractDeviceNameFromIdentityPayload(parsed);
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: typeof parsed.device_did === "string" ? parsed.device_did.trim() || null : null,
3926
- zoneDid: typeof parsed.zone_did === "string" ? parsed.zone_did.trim() || null : null,
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
- const deviceName = (metadata == null ? void 0 : metadata.deviceName) ?? null;
3968
- if (!deviceName || deviceName !== userId) {
4009
+ if (!metadata || metadata.deviceName !== userId) {
3969
4010
  continue;
3970
4011
  }
3971
- for (const keyPath of await this.deviceKeyPathCandidates(dir, (metadata == null ? void 0 : metadata.deviceDid) ?? null)) {
3972
- const keyPem = await this.readPemFile(keyPath);
3973
- if (!keyPem) {
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
- // node_identity schema v2 stores the device authentication key in the
3987
- // identity-roots security dir (keyed by the device DID); v1 layouts keep a
3988
- // node_private_key.pem next to node_identity.json.
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 candidates = [];
3992
- if (deviceDid) {
3993
- try {
3994
- const dirName = DID.fromStr(deviceDid).toFilename();
3995
- const keyFileName = "authentication.private.pem";
3996
- candidates.push(path.join(identityDir, "security", dirName, keyFileName));
3997
- const env = getProcessEnv();
3998
- const securityRoot = trimToNull$2(env.BUCKYOS_SECURITY_ROOT) ?? path.join(trimToNull$2(env.BUCKYOS_ROOT) ?? "/opt/buckyos", "security");
3999
- candidates.push(path.join(securityRoot, dirName, keyFileName));
4000
- } catch {
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
- candidates.push(path.join(identityDir, "node_private_key.pem"));
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 (!metadata) {
4078
- continue;
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 accountResponse = await verifyHubClient.loginByPassword({
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: normalized.user_name,
5194
- user_id: normalized.user_id,
5195
- user_type: normalized.user_type,
5196
- session_token: normalized.session_token,
5197
- refresh_token: normalized.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: normalized.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
- if (hostname.length > 0) {
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 errorMessage = "unknown error";
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
- errorMessage = result.message;
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: ${errorMessage}`, "OFFCHAIN_FAULT", { reason: "404_MISSING_RESOURCE", transaction: tx, info: { url, errorMessage } });
22203
- errorMessages.push(errorMessage);
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
- input.addEventListener("change", () => {
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
- reject(new NdmError("USER_CANCELLED", "No files selected"));
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
- const onFocus = () => {
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
- return { objectId: objId2.toString(), chunks, fileObject: fileObj2.toJSON() };
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
- return { objectId: objId.toString(), chunks, fileObject: fileObj.toJSON() };
27942
- }
27943
- async function materializeFileViaWorker(file, onHashProgress, chunkSize = DEFAULT_CHUNK_SIZE) {
27944
- if (!isHashWorkerAvailable()) {
27945
- return materializeFile(file, chunkSize);
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
- const session = hashFileInWorker(file, chunkSize);
27950
- if (onHashProgress) {
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(() => reject(new Error("hash worker timeout")), WORKER_TIMEOUT_MS);
27998
+ timer = setTimeout(() => {
27999
+ worker.cancel();
28000
+ reject(new Error("hash worker timeout"));
28001
+ }, 5 * 60 * 1e3);
27956
28002
  });
27957
- hashResults = await Promise.race([session.result, timeout]);
28003
+ hashResults = await Promise.race([worker.result, timeout]);
27958
28004
  } catch {
27959
- return materializeFile(file, chunkSize);
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
- return { objectId: objId2.toString(), chunks, fileObject: fileObj2.toJSON() };
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
- return { objectId: objId.toString(), chunks, fileObject: fileObj.toJSON() };
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
- const fileSize = file.size;
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 qcid = await tryCalculateQcidFromFile(file);
28020
- if (!qcid) {
28021
- throw new Error(`QCID requires file size >= ${MIN_QCID_FILE_SIZE} bytes`);
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
- if (!qcid) {
28104
+ throwIfCancelled(options.signal);
28105
+ if (!qcid)
28056
28106
  return null;
28057
- }
28058
- for (const scope of ["app", "global"]) {
28059
- try {
28060
- const response = await lookupObject(
28061
- { scope, quick_hash: qcid },
28062
- {
28063
- endpoint,
28064
- sessionToken: getActiveRuntimeType() === RuntimeType.Browser ? null : void 0
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
- return null;
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
- const firstPath = files[0].webkitRelativePath;
28086
- const rootName = firstPath ? firstPath.split("/")[0] : "directory";
28087
- const root = {
28088
- kind: "dir",
28089
- objectId: "",
28090
- // will be computed later
28091
- name: rootName,
28092
- children: []
28093
- };
28094
- const dirMap = /* @__PURE__ */ new Map();
28095
- dirMap.set("", root);
28096
- for (const fileObj of fileObjects) {
28097
- const relPath = fileObj.relativePath ?? fileObj.name;
28098
- const parts = relPath.split("/");
28099
- const pathParts = parts.length > 1 ? parts.slice(1) : parts;
28100
- let currentDir = root;
28101
- for (let i = 0; i < pathParts.length - 1; i++) {
28102
- const dirName = pathParts[i];
28103
- const dirPath = pathParts.slice(0, i + 1).join("/");
28104
- let dir = dirMap.get(dirPath);
28105
- if (!dir) {
28106
- dir = {
28107
- kind: "dir",
28108
- objectId: "",
28109
- name: dirName,
28110
- relativePath: dirPath,
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
- const caps = currentProvider.getCapabilities();
28230
- if (options.mode === "single_dir" && !caps.canPickDirectory) {
28231
- throw new NdmError("DIRECTORY_NOT_SUPPORTED", "Current runtime does not support directory selection");
28232
- }
28233
- if (options.mode === "mixed" && !caps.canPickMixed) {
28234
- throw new NdmError("MODE_NOT_SUPPORTED_IN_RUNTIME", "Current runtime does not support mixed file/directory selection");
28235
- }
28236
- const files = await currentProvider.pickFiles(options);
28237
- if (files.length === 0) {
28238
- throw new NdmError("USER_CANCELLED", "No files selected");
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
- const relativePath = file.webkitRelativePath || void 0;
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
- const dirObj = buildDirTree(files, fileObjects);
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
- let materializationStatus = "ok";
28323
- if (allFilesAlreadyStored || caps.canUseNDMStore) {
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
- for (const [id2, state] of session.objectStates) {
28362
- perObjectProgress[id2] = {
28363
- objectId: state.objectId,
28364
- uploadedBytes: state.uploadedBytes,
28365
- totalBytes: state.size,
28366
- state: state.state
28367
- };
28368
- uploadedBytes += state.uploadedBytes;
28369
- if (state.state === "completed")
28370
- uploadedObjects++;
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, appId, fileHash, sessionToken, onProgress, signal) {
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 = `${appId}/${chunkInfo.chunkId}`;
28531
+ const logicalPath = chunkInfo.chunkId;
28412
28532
  let tusModule;
28413
28533
  try {
28414
- tusModule = await import("./tus_client-19baa342.mjs");
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
- headers: sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {},
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
- if (signal) {
28453
- signal.addEventListener("abort", () => {
28454
- upload.abort(true);
28455
- reject(new NdmError("UPLOAD_FAILED", "Upload aborted"));
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
- async function startUpload(sessionId, options) {
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
- if (session.uploadStatus === "completed" || session.uploadStatus === "not_required") {
28467
- return getImportSessionStatus(sessionId);
28468
- }
28469
- if (session.uploadStatus === "uploading") {
28470
- return getImportSessionStatus(sessionId);
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.abortController = new AbortController();
28479
- const concurrency = (options == null ? void 0 : options.concurrency) ?? 3;
28480
- let endpoint;
28481
- if (options == null ? void 0 : options.endpoint) {
28482
- endpoint = options.endpoint.replace(/\/+$/, "");
28483
- } else {
28484
- endpoint = typeof window !== "undefined" ? window.location.origin : "";
28485
- }
28486
- const sessionToken = (options == null ? void 0 : options.sessionToken) !== void 0 ? async () => options.sessionToken ?? null : async () => getActiveSessionToken().catch(() => null);
28487
- doUpload(session, endpoint, concurrency, sessionToken).catch(() => {
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 doUpload(session, endpoint, concurrency, sessionToken) {
28492
- const states = Array.from(session.objectStates.values()).filter((s) => s.state !== "completed");
28493
- let running = 0;
28494
- let idx = 0;
28495
- let hasError = false;
28496
- await new Promise((resolve, reject) => {
28497
- function next() {
28498
- if (hasError)
28499
- return;
28500
- if (idx >= states.length && running === 0) {
28501
- const allCompleted = Array.from(session.objectStates.values()).every((s) => s.state === "completed");
28502
- session.uploadStatus = allCompleted ? "completed" : "failed";
28503
- resolve();
28504
- return;
28505
- }
28506
- while (running < concurrency && idx < states.length) {
28507
- const state = states[idx++];
28508
- running++;
28509
- uploadSingleObject(session, endpoint, state, sessionToken).then(() => {
28510
- running--;
28511
- next();
28512
- }).catch(() => {
28513
- running--;
28514
- if (!hasError) {
28515
- hasError = true;
28516
- session.uploadStatus = "failed";
28517
- reject(new NdmError("UPLOAD_FAILED", `Upload of ${state.name} failed`));
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
- async function uploadSingleObject(session, endpoint, state, sessionToken) {
28526
- var _a2;
28527
- state.state = "uploading";
28528
- for (const [chunkIndex, chunk] of state.chunks.entries()) {
28529
- if (chunk.uploaded)
28530
- continue;
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
- state.uploadedBytes = state.size;
28548
- state.state = "completed";
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=ndm_proxy-6b03b9ec.mjs.map
29834
+ //# sourceMappingURL=executor_client-eb372968.mjs.map