@ibm-aspera/sdk 0.16.0 → 0.19.1

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.
@@ -11,14 +11,14 @@ var __assign = (this && this.__assign) || function () {
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.hasCapability = exports.getCapabilities = exports.readDirectory = exports.getChecksum = exports.readChunkAsArrayBuffer = exports.readAsArrayBuffer = exports.getInfo = exports.removeDropzone = exports.createDropzone = exports.setBranding = exports.modifyTransfer = exports.showDirectory = exports.getFilesList = exports.getTransfer = exports.getAllTransfers = exports.showTransferMonitor = exports.showPreferencesPage = exports.showTransferManager = exports.showPreferences = exports.showAbout = exports.showSaveFileDialog = exports.showSelectFolderDialog = exports.showSelectFileDialog = exports.resumeTransfer = exports.stopTransfer = exports.removeTransfer = exports.deregisterStatusCallback = exports.registerStatusCallback = exports.deregisterActivityCallback = exports.registerActivityCallback = exports.startTransfer = exports.authenticate = exports.testSshPorts = exports.init = exports.initDragDrop = exports.testConnection = void 0;
14
+ exports.hasCapability = exports.getCapabilities = exports.readDirectory = exports.getChecksum = exports.readChunkAsArrayBuffer = exports.readAsArrayBuffer = exports.getInfo = exports.removeDropzone = exports.createDropzone = exports.setBranding = exports.modifyTransfer = exports.showDirectory = exports.getFilesList = exports.getTransfer = exports.getAllTransfers = exports.showTransferMonitor = exports.showPreferencesPage = exports.showTransferManager = exports.showPreferences = exports.showAbout = exports.showSaveFileDialog = exports.showSelectFolderDialog = exports.showSelectFileDialog = exports.resumeTransfer = exports.stopTransfer = exports.removeTransfer = exports.deregisterStatusCallback = exports.registerStatusCallback = exports.deregisterActivityCallback = exports.registerActivityCallback = exports.startTransfer = exports.authenticate = exports.testSshPorts = exports.initSession = exports.init = exports.getStatus = exports.initDragDrop = exports.testConnection = void 0;
15
15
  var messages_1 = require("../constants/messages");
16
16
  var client_1 = require("../helpers/client/client");
17
17
  var helpers_1 = require("../helpers/helpers");
18
18
  var http_gateway_1 = require("../http-gateway");
19
19
  var core_1 = require("../http-gateway/core");
20
20
  var index_1 = require("../index");
21
- var connect_sdk_js_1 = require("@ibm-aspera/connect-sdk-js");
21
+ var status_1 = require("./status");
22
22
  var core_2 = require("../connect/core");
23
23
  /**
24
24
  * Check if IBM Aspera for Desktop connection works. This function is called by init
@@ -27,8 +27,7 @@ var core_2 = require("../connect/core");
27
27
  * @returns a promise that resolves if server can connect or rejects if not
28
28
  */
29
29
  var testConnection = function () {
30
- // FIXME: If force HTTP gateway is false this ends up preventing SDK from verifying IBM Aspera for desktop is running.
31
- if (index_1.asperaSdk.useHttpGateway || index_1.asperaSdk.useConnect) {
30
+ if (index_1.asperaSdk.isReady || index_1.asperaSdk.useConnect) {
32
31
  return Promise.resolve(index_1.asperaSdk.globals.sdkResponseData);
33
32
  }
34
33
  return client_1.client.request('get_info')
@@ -40,12 +39,16 @@ var testConnection = function () {
40
39
  };
41
40
  exports.testConnection = testConnection;
42
41
  /**
43
- * RPC discovery used internally when initializing the SDK.
42
+ * RPC discovery used internally during IBM Aspera for desktop initialization to determine
43
+ * the supported RPC methods of the user's version of IBM Aspera for desktop.
44
+ *
45
+ * For convenience, this function will return an empty [] if the SDK is currently configured to use
46
+ * either HTTP Gateway or Connect transfer clients.
44
47
  *
45
48
  * @returns a promise that resolves if discovery is successful
46
49
  */
47
50
  var rpcDiscover = function () {
48
- if (index_1.asperaSdk.useConnect || index_1.asperaSdk.useHttpGateway) {
51
+ if (index_1.asperaSdk.useHttpGateway || index_1.asperaSdk.useConnect) {
49
52
  return Promise.resolve({ methods: [] });
50
53
  }
51
54
  if (!index_1.asperaSdk.isReady) {
@@ -92,99 +95,222 @@ var initDragDrop = function (initCall) {
92
95
  };
93
96
  exports.initDragDrop = initDragDrop;
94
97
  /**
95
- * Initialize IBM Aspera client. If client cannot (reject/catch), then
96
- * client should attempt fixing server URL or trying again. If still fails disable UI elements.
97
- *
98
- * @param options initialization options:
99
- *
100
- * - `appId` the unique ID for the website. Transfers initiated during this session
101
- * will be associated with this ID. It is recommended to use a unique ID to keep transfer
102
- * information private from other websites.
98
+ * Get the current SDK lifecycle status synchronously.
103
99
  *
104
- * - `supportMultipleUsers` when enabled (defaults to false), the SDK will iterate over a port
105
- * range and generate a session id to determine the running instance of the desktop app for the
106
- * current user. This is needed when multiple users may be logged into the same machine
107
- * simultaneously, for example on a Windows Server.
108
- *
109
- * @returns a promise that resolves if IBM Aspera Desktop is running properly or
110
- * rejects if unable to connect
100
+ * @returns the current status, or undefined if no init has been called yet
111
101
  */
112
- var init = function (options) {
113
- var _a, _b, _c;
114
- var appId = (_a = options === null || options === void 0 ? void 0 : options.appId) !== null && _a !== void 0 ? _a : (0, helpers_1.randomUUID)();
115
- index_1.asperaSdk.globals.appId = appId;
102
+ var getStatus = function () {
103
+ return status_1.statusService.getStatus();
104
+ };
105
+ exports.getStatus = getStatus;
106
+ var setupAppId = function (options) {
107
+ var _a;
108
+ index_1.asperaSdk.globals.appId = (_a = options === null || options === void 0 ? void 0 : options.appId) !== null && _a !== void 0 ? _a : (0, helpers_1.randomUUID)();
116
109
  if (options === null || options === void 0 ? void 0 : options.supportMultipleUsers) {
117
110
  index_1.asperaSdk.globals.supportMultipleUsers = true;
118
111
  index_1.asperaSdk.globals.sessionId = (0, helpers_1.randomUUID)();
119
112
  }
113
+ };
114
+ var connectDesktop = function () {
115
+ return index_1.asperaSdk.activityTracking.setup()
116
+ .then(function () { return (0, exports.testConnection)(); })
117
+ .then(function () { return rpcDiscover(); })
118
+ .then(function () { return (0, exports.initDragDrop)(true); })
119
+ .then(function () { return undefined; });
120
+ };
121
+ /**
122
+ * Initialize the SDK and connect to a transfer client. Returns a promise that resolves
123
+ * when the transfer client is ready, or rejects if it cannot be reached.
124
+ *
125
+ * By default, the SDK connects to IBM Aspera for desktop. Set `connectSettings.useConnect`
126
+ * to use IBM Aspera Connect instead. If `httpGatewaySettings` is provided, the gateway is
127
+ * set up first — when `forceGateway` is true it becomes the sole transport; when false it
128
+ * is set up as a supplementary transport and the primary client (Desktop or Connect) is
129
+ * still initialized afterward.
130
+ *
131
+ * Note that the promise behavior varies by transfer client. For Desktop, the promise
132
+ * remains pending until the application is detected. For Connect, the promise resolves
133
+ * immediately after initialization begins — use {@link registerStatusCallback} to track
134
+ * when Connect is actually ready. For a non-blocking alternative that provides consistent
135
+ * lifecycle status events across all transfer clients, see {@link initSession}.
136
+ *
137
+ * @param options - Initialization options. See {@link InitOptions}.
138
+ *
139
+ * @returns a promise that resolves with SDK metadata when the transfer client is ready
140
+ *
141
+ * @example
142
+ * init({ appId: 'my-app' })
143
+ * .then(() => {
144
+ * // Transfer client is ready — enable UI
145
+ * })
146
+ * .catch(error => {
147
+ * // Could not connect — prompt user to install or launch
148
+ * });
149
+ */
150
+ var init = function (options) {
151
+ var _a;
152
+ setupAppId(options);
120
153
  var handleErrors = function (error) {
121
154
  (0, helpers_1.errorLog)(messages_1.messages.serverError, error);
122
155
  index_1.asperaSdk.globals.asperaAppVerified = false;
123
156
  throw (0, helpers_1.generateErrorBody)(messages_1.messages.serverError, error);
124
157
  };
125
- var getConnectStartCalls = function () {
126
- index_1.asperaSdk.globals.connect = new connect_sdk_js_1.Connect({
127
- minVersion: options.connectSettings.minVersion || '3.10.1',
128
- dragDropEnabled: options.connectSettings.dragDropEnabled,
129
- connectMethod: options.connectSettings.method,
130
- });
131
- index_1.asperaSdk.globals.connectInstaller = new connect_sdk_js_1.ConnectInstaller({
132
- sdkLocation: options.connectSettings.sdkLocation,
133
- correlationId: options.connectSettings.correlationId,
134
- style: 'carbon',
135
- version: options.connectSettings.version,
136
- });
137
- index_1.asperaSdk.globals.connectAW4 = {
138
- Connect: connect_sdk_js_1.Connect,
139
- ConnectInstaller: connect_sdk_js_1.ConnectInstaller,
140
- };
141
- return (0, core_2.initConnect)(!options.connectSettings.hideIncludedInstaller);
142
- };
143
158
  var getDesktopStartCalls = function () {
144
- return index_1.asperaSdk.activityTracking.setup()
145
- .then(function () { return (0, exports.testConnection)(); })
146
- .then(function () { return rpcDiscover(); })
147
- .then(function () { return (0, exports.initDragDrop)(true); })
159
+ return connectDesktop()
148
160
  .then(function () { return index_1.asperaSdk.globals.sdkResponseData; })
149
161
  .catch(handleErrors);
150
162
  };
151
- if (((_b = options === null || options === void 0 ? void 0 : options.httpGatewaySettings) === null || _b === void 0 ? void 0 : _b.url) && !index_1.asperaSdk.globals.httpGatewayVerified) {
152
- var finalHttpGatewayUrl = options.httpGatewaySettings.url.trim();
153
- if (finalHttpGatewayUrl.indexOf('http') !== 0) {
154
- finalHttpGatewayUrl = "https://".concat(finalHttpGatewayUrl);
155
- }
156
- if (finalHttpGatewayUrl.endsWith('/')) {
157
- finalHttpGatewayUrl = finalHttpGatewayUrl.slice(0, -1);
158
- }
159
- index_1.asperaSdk.globals.httpGatewayUrl = finalHttpGatewayUrl;
160
- return fetch("".concat(index_1.asperaSdk.globals.httpGatewayUrl, "/info"), { method: 'GET' }).then(function (response) {
161
- return response.json().then(function (responseData) {
162
- if (response.status >= 400) {
163
- throw Error(responseData);
164
- }
165
- return responseData;
166
- });
167
- }).then(function (response) {
168
- return (0, http_gateway_1.initHttpGateway)(response);
169
- }).then(function () {
170
- var _a, _b;
163
+ var getTransferClientCalls = function () {
164
+ var _a;
165
+ return ((_a = options === null || options === void 0 ? void 0 : options.connectSettings) === null || _a === void 0 ? void 0 : _a.useConnect) ? (0, core_2.initConnect)(options.connectSettings) : getDesktopStartCalls();
166
+ };
167
+ if (((_a = options === null || options === void 0 ? void 0 : options.httpGatewaySettings) === null || _a === void 0 ? void 0 : _a.url) && !index_1.asperaSdk.globals.httpGatewayVerified) {
168
+ return (0, http_gateway_1.setupHttpGateway)(options.httpGatewaySettings.url).then(function () {
169
+ var _a;
171
170
  if ((_a = options === null || options === void 0 ? void 0 : options.httpGatewaySettings) === null || _a === void 0 ? void 0 : _a.forceGateway) {
172
171
  return Promise.resolve(index_1.asperaSdk.globals.sdkResponseData);
173
172
  }
174
- return ((_b = options === null || options === void 0 ? void 0 : options.connectSettings) === null || _b === void 0 ? void 0 : _b.useConnect) ? getConnectStartCalls() : getDesktopStartCalls();
173
+ return getTransferClientCalls();
175
174
  }).catch(function (error) {
176
- var _a, _b;
177
- // If HTTP Gateway fails log and move on to transfer client
175
+ var _a;
178
176
  (0, helpers_1.errorLog)(messages_1.messages.httpInitFail, error);
179
177
  if ((_a = options === null || options === void 0 ? void 0 : options.httpGatewaySettings) === null || _a === void 0 ? void 0 : _a.forceGateway) {
180
178
  throw (0, helpers_1.generateErrorBody)(messages_1.messages.httpInitFail, error);
181
179
  }
182
- return ((_b = options === null || options === void 0 ? void 0 : options.connectSettings) === null || _b === void 0 ? void 0 : _b.useConnect) ? getConnectStartCalls() : getDesktopStartCalls();
180
+ return getTransferClientCalls();
183
181
  });
184
182
  }
185
- return ((_c = options === null || options === void 0 ? void 0 : options.connectSettings) === null || _c === void 0 ? void 0 : _c.useConnect) ? getConnectStartCalls() : getDesktopStartCalls();
183
+ return getTransferClientCalls();
186
184
  };
187
185
  exports.init = init;
186
+ /**
187
+ * Initialize the SDK and begin detecting a transfer client. This function returns
188
+ * immediately — lifecycle status is communicated asynchronously via {@link registerStatusCallback}.
189
+ *
190
+ * The SDK supports three transfer clients. By default, IBM Aspera for desktop is used.
191
+ * Set `connectSettings.useConnect` to use IBM Aspera Connect instead. Desktop and Connect
192
+ * are mutually exclusive — one or the other is detected, not both.
193
+ *
194
+ * ## HTTP Gateway
195
+ *
196
+ * HTTP Gateway is a server-side component that enables browser-based transfers without
197
+ * a desktop application. It can be used in two modes:
198
+ *
199
+ * - **Sole transport** (`forceGateway: true`): HTTP Gateway is the only transport.
200
+ * No Desktop or Connect detection occurs. Status transitions to `RUNNING` when the
201
+ * gateway responds successfully, or `FAILED` if it does not.
202
+ *
203
+ * - **Supplementary transport** (`forceGateway: false`): HTTP Gateway is set up first
204
+ * as an additional transport for browser-based uploads and downloads. The primary
205
+ * transfer client (Desktop or Connect) is then detected separately. If HTTP Gateway
206
+ * setup fails, the primary client is still detected. Features that require a desktop
207
+ * application (native file dialogs, drag and drop, etc.) are only available when the
208
+ * primary client is running.
209
+ *
210
+ * ## Status lifecycle
211
+ *
212
+ * Use {@link registerStatusCallback} to receive status updates. Use {@link getStatus} to
213
+ * read the current status synchronously at any time.
214
+ *
215
+ * **Desktop path**: `INITIALIZING` → `RUNNING` (app detected), `DEGRADED` (timeout but
216
+ * HTTP Gateway is available as a supplementary transport), or `FAILED` (timeout, no
217
+ * fallback). Detection continues in the background after `DEGRADED` or `FAILED` — if the
218
+ * user launches the app later, the status transitions to `RUNNING`.
219
+ *
220
+ * **Connect path**: `INITIALIZING` → `RUNNING`, `FAILED`, `OUTDATED`, or
221
+ * `EXTENSION_INSTALL` depending on the state of the Connect browser extension
222
+ * and application.
223
+ *
224
+ * **HTTP Gateway path** (`forceGateway: true`): `INITIALIZING` → `RUNNING` or `FAILED`.
225
+ *
226
+ * @param options - Initialization options. See {@link InitOptions}.
227
+ *
228
+ * @example
229
+ * // Detect IBM Aspera for desktop (default)
230
+ * initSession({ appId: 'my-app' });
231
+ *
232
+ * @example
233
+ * // Detect IBM Aspera for desktop with status handling
234
+ * registerStatusCallback(status => {
235
+ * if (status === 'RUNNING') {
236
+ * // Transfer client is ready — enable UI
237
+ * } else if (status === 'FAILED') {
238
+ * // Not detected — prompt user to install or launch
239
+ * }
240
+ * });
241
+ *
242
+ * initSession({ appId: 'my-app' });
243
+ *
244
+ * @example
245
+ * // Use IBM Aspera Connect
246
+ * initSession({
247
+ * appId: 'my-app',
248
+ * connectSettings: {
249
+ * useConnect: true,
250
+ * },
251
+ * });
252
+ *
253
+ * @example
254
+ * // Use HTTP Gateway as the sole transport (no desktop app needed)
255
+ * initSession({
256
+ * appId: 'my-app',
257
+ * httpGatewaySettings: {
258
+ * url: 'https://example.com/aspera/http-gwy',
259
+ * forceGateway: true,
260
+ * },
261
+ * });
262
+ *
263
+ * @example
264
+ * // HTTP Gateway as supplementary transport with Desktop as primary
265
+ * initSession({
266
+ * appId: 'my-app',
267
+ * httpGatewaySettings: {
268
+ * url: 'https://example.com/aspera/http-gwy',
269
+ * forceGateway: false,
270
+ * },
271
+ * });
272
+ */
273
+ var initSession = function (options) {
274
+ var _a, _b, _c;
275
+ setupAppId(options);
276
+ var retryInterval = (_a = options === null || options === void 0 ? void 0 : options.retryInterval) !== null && _a !== void 0 ? _a : 2000;
277
+ var retryTimeout = (_b = options === null || options === void 0 ? void 0 : options.retryTimeout) !== null && _b !== void 0 ? _b : 5000;
278
+ var startDesktopDetection = function () {
279
+ status_1.statusService.startPolling(connectDesktop, retryInterval, retryTimeout);
280
+ };
281
+ var startTransferClient = function () {
282
+ var _a;
283
+ if ((_a = options === null || options === void 0 ? void 0 : options.connectSettings) === null || _a === void 0 ? void 0 : _a.useConnect) {
284
+ (0, core_2.initConnect)(options.connectSettings);
285
+ }
286
+ else {
287
+ startDesktopDetection();
288
+ }
289
+ };
290
+ // HTTP Gateway path
291
+ if (((_c = options === null || options === void 0 ? void 0 : options.httpGatewaySettings) === null || _c === void 0 ? void 0 : _c.url) && !index_1.asperaSdk.globals.httpGatewayVerified) {
292
+ status_1.statusService.setStatus('INITIALIZING');
293
+ (0, http_gateway_1.setupHttpGateway)(options.httpGatewaySettings.url).then(function () {
294
+ var _a;
295
+ if ((_a = options === null || options === void 0 ? void 0 : options.httpGatewaySettings) === null || _a === void 0 ? void 0 : _a.forceGateway) {
296
+ status_1.statusService.setStatus('RUNNING');
297
+ return;
298
+ }
299
+ startTransferClient();
300
+ }).catch(function (error) {
301
+ var _a;
302
+ (0, helpers_1.errorLog)(messages_1.messages.httpInitFail, error);
303
+ if ((_a = options === null || options === void 0 ? void 0 : options.httpGatewaySettings) === null || _a === void 0 ? void 0 : _a.forceGateway) {
304
+ status_1.statusService.setStatus('FAILED');
305
+ return;
306
+ }
307
+ startTransferClient();
308
+ });
309
+ return;
310
+ }
311
+ startTransferClient();
312
+ };
313
+ exports.initSession = initSession;
188
314
  /**
189
315
  * Tests SSH port connectivity to a transfer server.
190
316
  *
@@ -319,18 +445,46 @@ var deregisterActivityCallback = function (id) {
319
445
  };
320
446
  exports.deregisterActivityCallback = deregisterActivityCallback;
321
447
  /**
322
- * Register a callback for getting updates about the connection status of IBM Aspera SDK.
448
+ * Register a callback for SDK lifecycle status changes. The callback fires immediately
449
+ * with the current status (if one exists) and again whenever the status changes.
323
450
  *
324
- * For example, to be notified of when the SDK loses connection with the application or connection
325
- * is re-established. This can be useful if you want to handle the case where the user quits IBM Aspera
326
- * after `init` has already been called, and want to prompt the user to relaunch the application.
451
+ * Status values:
327
452
  *
328
- * @param callback callback function to receive events
453
+ * - `INITIALIZING` The SDK is detecting a transfer client.
454
+ * - `RUNNING` — A transfer client is ready. Full functionality is available.
455
+ * - `DEGRADED` — The primary transfer client (IBM Aspera for desktop) was not detected, but HTTP
456
+ * Gateway is available as a fallback. This is only available if XXX...
457
+ * - `FAILED` — No transfer client could be reached. This could be because the user does
458
+ * not have a transfer client installed, it is not running, or in the case of HTTP Gateway,
459
+ * it was not reachable.
460
+ * - `DISCONNECTED` — The transfer client was previously running but lost connection. This is specific
461
+ * to IBM Aspera for desktop. For example, if the user quits the app this status will trigger.
462
+ * - `OUTDATED` — (Connect only) The Connect installation needs updating.
463
+ * - `EXTENSION_INSTALL` — (Connect only) The browser extension needs to be installed.
464
+ *
465
+ * For IBM Aspera for desktop, detection continues in the background after `FAILED` or `DEGRADED`.
466
+ * If the user launches the application later, the status transitions to `RUNNING`.
467
+ *
468
+ * @param callback callback function to receive status events
329
469
  *
330
470
  * @returns ID representing the callback for deregistration purposes
471
+ *
472
+ * @example
473
+ * const id = registerStatusCallback(status => {
474
+ * if (status === 'RUNNING') {
475
+ * // Full functionality — enable all UI
476
+ * } else if (status === 'DEGRADED') {
477
+ * // Transfers work via HTTP Gateway
478
+ * } else if (status === 'FAILED') {
479
+ * // Nothing available — prompt user to install
480
+ * }
481
+ * });
482
+ *
483
+ * // Later, to stop listening:
484
+ * deregisterStatusCallback(id);
331
485
  */
332
486
  var registerStatusCallback = function (callback) {
333
- return index_1.asperaSdk.activityTracking.setWebSocketEventCallback(callback);
487
+ return status_1.statusService.registerCallback(callback);
334
488
  };
335
489
  exports.registerStatusCallback = registerStatusCallback;
336
490
  /**
@@ -339,7 +493,7 @@ exports.registerStatusCallback = registerStatusCallback;
339
493
  * @param id the ID returned by `registerStatusCallback`
340
494
  */
341
495
  var deregisterStatusCallback = function (id) {
342
- index_1.asperaSdk.activityTracking.removeWebSocketEventCallback(id);
496
+ status_1.statusService.deregisterCallback(id);
343
497
  };
344
498
  exports.deregisterStatusCallback = deregisterStatusCallback;
345
499
  /**
@@ -1188,6 +1342,10 @@ var readDirectory = function (options) {
1188
1342
  };
1189
1343
  exports.readDirectory = readDirectory;
1190
1344
  var supportsMethod = function (method) {
1345
+ // HTTP Gateway v2 specific overrides
1346
+ if (index_1.asperaSdk.useOldHttpGateway && (method === 'read_as_array_buffer' || method === 'read_chunk_as_array_buffer')) {
1347
+ return false;
1348
+ }
1191
1349
  // We currently do not support calculating file checksums when using HTTP Gateway. In theory it should be possible
1192
1350
  // to calculate this directly in the browser similar to how `readAsArrayBuffer()` is implemented.
1193
1351
  // HTTP Gateway also does not support showing native transfer client UI (about, preferences, etc.).
@@ -1208,11 +1366,12 @@ var supportsMethod = function (method) {
1208
1366
  * Returns an object describing the high-level capabilities supported by the user's
1209
1367
  * transfer client (e.g. IBM Aspera for desktop, Connect, or HTTP Gateway).
1210
1368
  *
1211
- * Use this for feature detection at a semantic level rather than checking individual RPC methods.
1212
- * Capabitilies may depend on multiple underlying RPC methods and also may vary by transfer client.
1369
+ * Use this for feature detection at a semantic level as capabilities may change depending on the
1370
+ * transfer client.
1213
1371
  *
1214
- * Some capabitilies may depend on newer versions of the transfer client. This function may be useful
1215
- * if you want to conditionally perform certain actions rather than potentially getting an error.
1372
+ * Rather than caching the return value of this function, it's recommended to call it on the fly as
1373
+ * capabilities may change if your application supports multiple transfer clients. As a result, it's
1374
+ * recommend to use the slightly more ergonomic {@link hasCapability}.
1216
1375
  *
1217
1376
  * @returns an object with boolean flags for each capability.
1218
1377
  *
@@ -1240,10 +1399,18 @@ var getCapabilities = function () {
1240
1399
  };
1241
1400
  exports.getCapabilities = getCapabilities;
1242
1401
  /**
1243
- * Check if the SDK and underlying transfer client supports a specific capability.
1402
+ * Check if the SDK and underlying transfer client supports a specific capability or feature.
1244
1403
  *
1245
1404
  * Capabilities depend on the transfer client being used (HTTP Gateway, Connect, or IBM Aspera for desktop).
1246
- * Use this function to conditionally enable/disable features in your application.
1405
+ *
1406
+ * This function may be useful if you want to conditionally perform certain actions rather than
1407
+ * potentially getting an error.
1408
+ *
1409
+ * For example, only IBM Aspera for desktop supports traversing a folder's contents. An application can
1410
+ * check `hasCapability('readDirectory')` to optionally show a folder browser only when the feature is available.
1411
+ * For example, when a user does not have IBM Aspera for desktop installed and is using HTTP Gateway, your
1412
+ * application can disable this feature. Later, if that same user installs IBM Aspera for desktop, your application
1413
+ * will show the feature as enabled without any additional changes.
1247
1414
  *
1248
1415
  * @param capability the capability to check.
1249
1416
  *
@@ -1253,7 +1420,7 @@ exports.getCapabilities = getCapabilities;
1253
1420
  * ```typescript
1254
1421
  * // Determine if your web application can render image previews for user selected files
1255
1422
  * if (asperaSdk.hasCapability('imagePreview')) {
1256
- * asperaSdk.readAsArrayBuffer(path);
1423
+ * const response = await asperaSdk.readAsArrayBuffer(path);
1257
1424
  * }
1258
1425
  * ```
1259
1426
  */
@@ -0,0 +1,24 @@
1
+ import { SdkStatus } from '../models/models';
2
+ type StatusCallback = (status: SdkStatus) => void;
3
+ declare class StatusService {
4
+ private currentStatus;
5
+ private callbacks;
6
+ private pollTimerId;
7
+ private failTimeoutId;
8
+ getStatus(): SdkStatus | undefined;
9
+ setStatus(status: SdkStatus): void;
10
+ registerCallback(cb: StatusCallback): string;
11
+ deregisterCallback(id: string): void;
12
+ /**
13
+ * Start Desktop detection polling loop.
14
+ *
15
+ * @param detectFn async function that resolves if Desktop is found, rejects if not
16
+ * @param interval ms between attempts
17
+ * @param failTimeout ms before transitioning to FAILED or DEGRADED
18
+ */
19
+ startPolling(detectFn: () => Promise<void>, interval: number, failTimeout: number): void;
20
+ stopPolling(): void;
21
+ reset(): void;
22
+ }
23
+ export declare const statusService: StatusService;
24
+ export {};
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.statusService = void 0;
4
+ var helpers_1 = require("../helpers/helpers");
5
+ var index_1 = require("../index");
6
+ var StatusService = /** @class */ (function () {
7
+ function StatusService() {
8
+ this.currentStatus = undefined;
9
+ this.callbacks = new Map();
10
+ this.pollTimerId = null;
11
+ this.failTimeoutId = null;
12
+ }
13
+ StatusService.prototype.getStatus = function () {
14
+ return this.currentStatus;
15
+ };
16
+ StatusService.prototype.setStatus = function (status) {
17
+ // When Desktop disconnects, remap to DEGRADED if HTTP Gateway is available
18
+ if (status === 'DISCONNECTED' && index_1.asperaSdk.httpGatewayIsReady) {
19
+ status = 'DEGRADED';
20
+ }
21
+ if (this.currentStatus === status) {
22
+ return;
23
+ }
24
+ // Manage Desktop verification state based on status transitions
25
+ if (status === 'DISCONNECTED' || status === 'DEGRADED') {
26
+ index_1.asperaSdk.globals.asperaAppVerified = false;
27
+ }
28
+ else if (status === 'RUNNING' && (this.currentStatus === 'DISCONNECTED' || this.currentStatus === 'DEGRADED')) {
29
+ index_1.asperaSdk.globals.asperaAppVerified = true;
30
+ }
31
+ this.currentStatus = status;
32
+ this.callbacks.forEach(function (cb) { return cb(status); });
33
+ };
34
+ StatusService.prototype.registerCallback = function (cb) {
35
+ var id = "status-".concat((0, helpers_1.randomUUID)());
36
+ this.callbacks.set(id, cb);
37
+ if (this.currentStatus !== undefined) {
38
+ cb(this.currentStatus);
39
+ }
40
+ return id;
41
+ };
42
+ StatusService.prototype.deregisterCallback = function (id) {
43
+ this.callbacks.delete(id);
44
+ };
45
+ /**
46
+ * Start Desktop detection polling loop.
47
+ *
48
+ * @param detectFn async function that resolves if Desktop is found, rejects if not
49
+ * @param interval ms between attempts
50
+ * @param failTimeout ms before transitioning to FAILED or DEGRADED
51
+ */
52
+ StatusService.prototype.startPolling = function (detectFn, interval, failTimeout) {
53
+ var _this = this;
54
+ this.stopPolling();
55
+ this.setStatus('INITIALIZING');
56
+ this.failTimeoutId = setTimeout(function () {
57
+ if (_this.currentStatus !== 'RUNNING') {
58
+ if (index_1.asperaSdk.httpGatewayIsReady) {
59
+ _this.setStatus('DEGRADED');
60
+ }
61
+ else {
62
+ _this.setStatus('FAILED');
63
+ }
64
+ }
65
+ }, failTimeout);
66
+ var attempt = function () {
67
+ detectFn()
68
+ .then(function () {
69
+ _this.stopPolling();
70
+ _this.setStatus('RUNNING');
71
+ })
72
+ .catch(function () {
73
+ // Stay in current status (INITIALIZING or FAILED), poll continues
74
+ });
75
+ };
76
+ attempt();
77
+ this.pollTimerId = setInterval(attempt, interval);
78
+ };
79
+ StatusService.prototype.stopPolling = function () {
80
+ if (this.pollTimerId) {
81
+ clearInterval(this.pollTimerId);
82
+ this.pollTimerId = null;
83
+ }
84
+ if (this.failTimeoutId) {
85
+ clearTimeout(this.failTimeoutId);
86
+ this.failTimeoutId = null;
87
+ }
88
+ };
89
+ StatusService.prototype.reset = function () {
90
+ this.stopPolling();
91
+ this.currentStatus = undefined;
92
+ this.callbacks.clear();
93
+ };
94
+ return StatusService;
95
+ }());
96
+ exports.statusService = new StatusService();
@@ -1,4 +1,5 @@
1
1
  import * as ConnectTypes from '@ibm-aspera/connect-sdk-js/dist/esm/core/types';
2
+ import { InitOptions } from '../models/models';
2
3
  /**
3
4
  * Connect Core Logic
4
5
  *
@@ -8,4 +9,4 @@ import * as ConnectTypes from '@ibm-aspera/connect-sdk-js/dist/esm/core/types';
8
9
  */
9
10
  export declare const handleTransfers: (transfers: ConnectTypes.TransferInfo[]) => void;
10
11
  export declare const connectInstallationFlow: () => void;
11
- export declare const initConnect: (useIncludedInstaller?: boolean) => Promise<unknown>;
12
+ export declare const initConnect: (connectSettings: InitOptions["connectSettings"]) => Promise<unknown>;
@@ -51,7 +51,22 @@ var connectInstallationFlow = function () {
51
51
  index_1.asperaSdk.globals.connect.addEventListener(index_1.asperaSdk.globals.connectAW4.Connect.EVENT.STATUS, handleInstallerEvent);
52
52
  };
53
53
  exports.connectInstallationFlow = connectInstallationFlow;
54
- var initConnect = function (useIncludedInstaller) {
54
+ var initConnect = function (connectSettings) {
55
+ index_1.asperaSdk.globals.connect = new connect_sdk_js_1.Connect({
56
+ minVersion: connectSettings.minVersion || '3.10.1',
57
+ dragDropEnabled: connectSettings.dragDropEnabled,
58
+ connectMethod: connectSettings.method,
59
+ });
60
+ index_1.asperaSdk.globals.connectInstaller = new connect_sdk_js_1.ConnectInstaller({
61
+ sdkLocation: connectSettings.sdkLocation,
62
+ correlationId: connectSettings.correlationId,
63
+ style: 'carbon',
64
+ version: connectSettings.version,
65
+ });
66
+ index_1.asperaSdk.globals.connectAW4 = {
67
+ Connect: connect_sdk_js_1.Connect,
68
+ ConnectInstaller: connect_sdk_js_1.ConnectInstaller,
69
+ };
55
70
  index_1.asperaSdk.globals.connect.addEventListener(connect_sdk_js_1.Connect.EVENT.STATUS, function (eventType, eventStatus) {
56
71
  if (eventType === connect_sdk_js_1.Connect.EVENT.STATUS) {
57
72
  index_1.asperaSdk.globals.connectStatus = eventStatus;
@@ -65,7 +80,7 @@ var initConnect = function (useIncludedInstaller) {
65
80
  }
66
81
  });
67
82
  index_1.asperaSdk.globals.connect.initSession(index_1.asperaSdk.globals.appId);
68
- if (useIncludedInstaller) {
83
+ if (!connectSettings.hideIncludedInstaller) {
69
84
  (0, exports.connectInstallationFlow)();
70
85
  }
71
86
  return Promise.resolve({ connectMode: true });
@@ -24,7 +24,7 @@ exports.messages = {
24
24
  showSelectFolderDialogFailed: 'Unable to show select folder dialog',
25
25
  showPreferencesFailed: 'Unable to show preferences',
26
26
  stopTransferFailed: 'Unable to stop transfer',
27
- stopTransferFailedExternal: 'Unable to stop transfer. The download must be canceled from the browser\'s download manager',
27
+ stopTransferFailedExternal: 'Unable to stop transfer. The download must be cancelled from the browser\'s download manager',
28
28
  transferFailed: 'The transfer failed to initiate',
29
29
  unableToFindElementOnPage: 'Unable to find the element on the current page',
30
30
  unableToReadDropped: 'The dropped item could not be parsed. Please try selecting via the select file/folder option',
@@ -33,7 +33,7 @@ exports.messages = {
33
33
  websocketNotReady: 'The websocket is not ready. Run init first',
34
34
  httpNotAvailable: 'IBM Aspera HTTP Gateway is not available',
35
35
  httpInitFail: 'IBM Aspera HTTP Gateway could not be started',
36
- filePickerCancel: 'User canceled the select file or folder dialog.',
36
+ filePickerCancel: 'User cancelled the select file or folder dialog.',
37
37
  fileNotAllowed: 'The specified path has not been allowed by the user.',
38
38
  httpNetworkFail: 'HTTP network encountered unknown error.',
39
39
  readAsArrayBufferFailed: 'Unable to read file as array buffer',
@@ -53,6 +53,11 @@ export declare class WebsocketService {
53
53
  */
54
54
  init(): Promise<unknown>;
55
55
  private connect;
56
+ /**
57
+ * Detach event handlers from the current socket so it cannot fire
58
+ * stale CLOSED/RECONNECT events after being replaced.
59
+ */
60
+ private detachSocket;
56
61
  private reconnect;
57
62
  private getWebSocketConnection;
58
63
  private notifyEvent;