@absolutejs/absolute 0.20.0-beta.84 → 0.20.0-beta.85

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.
@@ -157,17 +157,18 @@ var fileUrl = (manifestUrl, releaseId, path) => {
157
157
  throw new TypeError("Mobile update asset escaped its signed release origin.");
158
158
  return result;
159
159
  };
160
- var readChunks = async (reader, maximum, chunks = [], received = 0) => {
160
+ var readChunks = async (reader, maximum, onChunk, chunks = [], received = 0) => {
161
161
  const result = await reader.read();
162
162
  if (result.done)
163
163
  return { chunks, received };
164
164
  const total = received + result.value.byteLength;
165
165
  if (total > maximum)
166
166
  throw new TypeError("Mobile update response exceeds its signed size.");
167
+ await onChunk?.(result.value, received);
167
168
  chunks.push(result.value);
168
- return readChunks(reader, maximum, chunks, total);
169
+ return readChunks(reader, maximum, onChunk, chunks, total);
169
170
  };
170
- var readBounded = async (response, maximum) => {
171
+ var readBounded = async (response, maximum, onChunk) => {
171
172
  const declared = Number(response.headers.get("content-length"));
172
173
  if (Number.isFinite(declared) && declared > maximum)
173
174
  throw new TypeError("Mobile update response exceeds its signed size.");
@@ -175,8 +176,9 @@ var readBounded = async (response, maximum) => {
175
176
  return new Uint8Array;
176
177
  const reader = response.body.getReader();
177
178
  let result;
179
+ const chunks = [];
178
180
  try {
179
- result = await readChunks(reader, maximum);
181
+ result = await readChunks(reader, maximum, onChunk, chunks);
180
182
  } catch (error) {
181
183
  await reader.cancel().catch(() => {
182
184
  return;
@@ -185,7 +187,7 @@ var readBounded = async (response, maximum) => {
185
187
  }
186
188
  const contents = new Uint8Array(result.received);
187
189
  let offset = 0;
188
- for (const chunk of result.chunks) {
190
+ for (const chunk of chunks) {
189
191
  contents.set(chunk, offset);
190
192
  offset += chunk.byteLength;
191
193
  }
@@ -206,49 +208,172 @@ var requireCompatible = (manifest, config) => {
206
208
  if (manifest.runtimeFingerprint !== config.runtimeFingerprint)
207
209
  throw new TypeError("Mobile update requires a different native runtime.");
208
210
  };
211
+ var networkConcurrency = (requested) => {
212
+ const bounded = Math.max(1, Math.min(6, Math.floor(requested ?? 3)));
213
+ const navigatorValue = Reflect.get(globalThis, "navigator");
214
+ const connection = typeof navigatorValue === "object" && navigatorValue !== null ? Reflect.get(navigatorValue, "connection") : undefined;
215
+ if (typeof connection !== "object" || connection === null)
216
+ return bounded;
217
+ if (Reflect.get(connection, "saveData") === true)
218
+ return 1;
219
+ const effectiveType = Reflect.get(connection, "effectiveType");
220
+ if (effectiveType === "slow-2g" || effectiveType === "2g")
221
+ return 1;
222
+ if (effectiveType === "3g")
223
+ return Math.min(2, bounded);
224
+ return bounded;
225
+ };
226
+ var combine = (prefix, suffix) => {
227
+ const result = new Uint8Array(prefix.byteLength + suffix.byteLength);
228
+ result.set(prefix);
229
+ result.set(suffix, prefix.byteLength);
230
+ return result;
231
+ };
232
+ var validContentRange = (value, start, total) => value === `bytes ${start}-${total - 1}/${total}`;
233
+ var combineSignals = (signals) => {
234
+ const nativeAny = Reflect.get(AbortSignal, "any");
235
+ if (typeof nativeAny === "function")
236
+ return Reflect.apply(nativeAny, AbortSignal, [signals]);
237
+ const controller = new AbortController;
238
+ const abort = () => controller.abort();
239
+ if (signals.some((signal) => signal.aborted))
240
+ abort();
241
+ else
242
+ signals.forEach((signal) => signal.addEventListener("abort", abort, { once: true }));
243
+ return controller.signal;
244
+ };
209
245
  var createAbsoluteMobileUpdateClient = (options) => {
210
246
  const manifestUrl = exactManifestUrl(options.config.manifestUrl);
211
247
  const request = options.fetch ?? globalThis.fetch;
212
- const downloadFiles = async (manifest, index = 0, transfer = {
213
- downloadedBytes: 0,
214
- downloadedFiles: 0,
215
- reusedBytes: 0,
216
- reusedFiles: 0,
217
- totalBytes: manifest.files.reduce((total, file) => total + file.bytes, 0),
218
- totalFiles: manifest.files.length
219
- }) => {
220
- const file = manifest.files[index];
221
- if (!file)
222
- return transfer;
223
- const reusable = await options.store.readReusable?.(file);
224
- if (reusable && reusable.byteLength === file.bytes && await options.verifier.digest(reusable) === file.sha256) {
225
- await options.store.write(file, reusable);
226
- return downloadFiles(manifest, index + 1, {
227
- ...transfer,
228
- reusedBytes: transfer.reusedBytes + reusable.byteLength,
229
- reusedFiles: transfer.reusedFiles + 1
248
+ const downloadFiles = async (manifest) => {
249
+ const startedAt = performance.now();
250
+ const transfer = {
251
+ avoidedBytes: 0,
252
+ completedFiles: 0,
253
+ downloadedBytes: 0,
254
+ downloadedFiles: 0,
255
+ durationMs: 0,
256
+ resumedBytes: 0,
257
+ resumedFiles: 0,
258
+ reusedBytes: 0,
259
+ reusedFiles: 0,
260
+ throughputBytesPerSecond: 0,
261
+ totalBytes: manifest.files.reduce((total, file) => total + file.bytes, 0),
262
+ totalFiles: manifest.files.length
263
+ };
264
+ const updateTiming = () => {
265
+ transfer.durationMs = Math.max(0, performance.now() - startedAt);
266
+ transfer.avoidedBytes = transfer.reusedBytes + transfer.resumedBytes;
267
+ transfer.throughputBytesPerSecond = transfer.durationMs > 0 ? Math.round(transfer.downloadedBytes * 1000 / transfer.durationMs) : transfer.downloadedBytes;
268
+ };
269
+ const progress = () => {
270
+ updateTiming();
271
+ try {
272
+ options.onProgress?.({
273
+ ...transfer,
274
+ kind: "download-progress"
275
+ });
276
+ } catch {}
277
+ };
278
+ const controller = new AbortController;
279
+ let next = 0;
280
+ let firstError;
281
+ const downloadFile = async (file) => {
282
+ const staged = await options.store.readStaged?.(file);
283
+ if (staged?.byteLength === file.bytes && await options.verifier.digest(staged) === file.sha256) {
284
+ transfer.resumedBytes += staged.byteLength;
285
+ transfer.resumedFiles += 1;
286
+ transfer.completedFiles += 1;
287
+ progress();
288
+ return;
289
+ }
290
+ const reusable = await options.store.readReusable?.(file);
291
+ if (reusable?.byteLength === file.bytes && await options.verifier.digest(reusable) === file.sha256) {
292
+ await options.store.write(file, reusable);
293
+ transfer.reusedBytes += reusable.byteLength;
294
+ transfer.reusedFiles += 1;
295
+ transfer.completedFiles += 1;
296
+ progress();
297
+ return;
298
+ }
299
+ const candidate = await options.store.readPartial?.(file);
300
+ if (candidate?.byteLength === file.bytes && await options.verifier.digest(candidate) === file.sha256) {
301
+ await options.store.write(file, candidate);
302
+ transfer.resumedBytes += candidate.byteLength;
303
+ transfer.resumedFiles += 1;
304
+ transfer.completedFiles += 1;
305
+ progress();
306
+ return;
307
+ }
308
+ const partial = candidate && candidate.byteLength > 0 && candidate.byteLength < file.bytes ? candidate : new Uint8Array;
309
+ const headers = new Headers;
310
+ if (partial.byteLength > 0) {
311
+ headers.set("if-range", `"${file.sha256}"`);
312
+ headers.set("range", `bytes=${partial.byteLength}-`);
313
+ }
314
+ const asset = await request(fileUrl(manifestUrl, manifest.releaseId, file.path), {
315
+ cache: "no-store",
316
+ credentials: "omit",
317
+ headers,
318
+ redirect: "error",
319
+ signal: combineSignals([
320
+ controller.signal,
321
+ AbortSignal.timeout(30000)
322
+ ])
230
323
  });
231
- }
232
- const asset = await request(fileUrl(manifestUrl, manifest.releaseId, file.path), {
233
- cache: "no-store",
234
- credentials: "omit",
235
- redirect: "error",
236
- signal: AbortSignal.timeout(30000)
237
- });
238
- if (!asset.ok)
239
- throw new TypeError(`Mobile update asset ${file.path} failed with HTTP ${asset.status}.`);
240
- const contents = await readBounded(asset, file.bytes);
241
- const downloadedBytes = transfer.downloadedBytes + contents.byteLength;
242
- if (contents.byteLength !== file.bytes || downloadedBytes > ABSOLUTE_MOBILE_UPDATE_MAX_TOTAL_BYTES)
243
- throw new TypeError(`Mobile update asset ${file.path} has an invalid size.`);
244
- if (await options.verifier.digest(contents) !== file.sha256)
245
- throw new TypeError(`Mobile update asset ${file.path} failed integrity verification.`);
246
- await options.store.write(file, contents);
247
- return downloadFiles(manifest, index + 1, {
248
- ...transfer,
249
- downloadedBytes,
250
- downloadedFiles: transfer.downloadedFiles + 1
251
- });
324
+ if (!asset.ok)
325
+ throw new TypeError(`Mobile update asset ${file.path} failed with HTTP ${asset.status}.`);
326
+ const ranged = asset.status === 206;
327
+ if (ranged && (partial.byteLength === 0 || !validContentRange(asset.headers.get("content-range"), partial.byteLength, file.bytes)))
328
+ throw new TypeError(`Mobile update asset ${file.path} returned an invalid byte range.`);
329
+ const prefix = ranged ? partial : new Uint8Array;
330
+ if (ranged) {
331
+ transfer.resumedBytes += partial.byteLength;
332
+ transfer.resumedFiles += 1;
333
+ }
334
+ const downloaded = await readBounded(asset, file.bytes - prefix.byteLength, options.store.appendPartial ? async (chunk, offset) => {
335
+ await options.store.appendPartial?.(file, chunk, prefix.byteLength + offset);
336
+ transfer.downloadedBytes += chunk.byteLength;
337
+ progress();
338
+ } : undefined);
339
+ if (!options.store.appendPartial) {
340
+ transfer.downloadedBytes += downloaded.byteLength;
341
+ progress();
342
+ }
343
+ if (transfer.downloadedBytes > ABSOLUTE_MOBILE_UPDATE_MAX_TOTAL_BYTES)
344
+ throw new TypeError("Mobile update exceeds the maximum transfer size.");
345
+ const contents = combine(prefix, downloaded);
346
+ if (contents.byteLength !== file.bytes)
347
+ throw new TypeError(`Mobile update asset ${file.path} has an invalid size.`);
348
+ if (await options.verifier.digest(contents) !== file.sha256)
349
+ throw new TypeError(`Mobile update asset ${file.path} failed integrity verification.`);
350
+ await options.store.write(file, contents);
351
+ transfer.downloadedFiles += 1;
352
+ transfer.completedFiles += 1;
353
+ progress();
354
+ };
355
+ const worker = async () => {
356
+ if (firstError)
357
+ return;
358
+ const index = next++;
359
+ const file = manifest.files[index];
360
+ if (!file)
361
+ return;
362
+ try {
363
+ await downloadFile(file);
364
+ } catch (error) {
365
+ firstError ??= error;
366
+ controller.abort();
367
+ }
368
+ await worker();
369
+ };
370
+ await Promise.all(Array.from({
371
+ length: Math.min(networkConcurrency(options.concurrency), manifest.files.length)
372
+ }, () => worker()));
373
+ if (firstError)
374
+ throw firstError;
375
+ updateTiming();
376
+ return transfer;
252
377
  };
253
378
  const check = async (download = false) => {
254
379
  const response = await request(manifestUrl, {
@@ -285,7 +410,10 @@ var createAbsoluteMobileUpdateClient = (options) => {
285
410
  transfer = await downloadFiles(manifest);
286
411
  await options.store.commit(manifest);
287
412
  } catch (error) {
288
- await options.store.abort(manifest.releaseId);
413
+ if (options.store.suspend)
414
+ await options.store.suspend(manifest.releaseId);
415
+ else
416
+ await options.store.abort(manifest.releaseId);
289
417
  throw error;
290
418
  }
291
419
  return { kind: "downloaded", manifest, transfer };
@@ -299,10 +427,12 @@ var createAbsoluteMobileUpdateClient = (options) => {
299
427
 
300
428
  // src/mobile/shellUpdate.ts
301
429
  var STATE_KEY = "absolute.mobile.update.state.v1";
430
+ var STAGING_KEY = "absolute.mobile.update.staging.v1";
302
431
  var INSTALLATION_KEY = "absolute.mobile.update.installation.v1";
303
432
  var RESULT_KEY = Symbol.for("absolutejs.mobile.update.result");
304
433
  var RESULTS_KEY = Symbol.for("absolutejs.mobile.update.results");
305
434
  var ROOT = "NoCloud/ionic_built_snapshots";
435
+ var STAGING_ROOT = "NoCloud/absolute_update_staging";
306
436
  var watchdog = registerPlugin("AbsoluteMobileUpdateWatchdog");
307
437
  var base64Bytes = (value) => Uint8Array.from(atob(value), (character) => character.charCodeAt(0));
308
438
  var arrayBuffer = (value) => new Uint8Array(value).buffer;
@@ -361,6 +491,25 @@ var readState = async () => {
361
491
  }
362
492
  };
363
493
  var writeState = (state) => Preferences.set({ key: STATE_KEY, value: JSON.stringify(state) });
494
+ var clearStagingRoot = () => Filesystem.rmdir({
495
+ directory: Directory.Library,
496
+ path: STAGING_ROOT,
497
+ recursive: true
498
+ }).catch(() => {
499
+ return;
500
+ });
501
+ var readStaging = async () => {
502
+ const { value } = await Preferences.get({ key: STAGING_KEY });
503
+ if (!value)
504
+ return;
505
+ try {
506
+ return parseAbsoluteMobileUpdateManifest(JSON.parse(value));
507
+ } catch {
508
+ await Preferences.remove({ key: STAGING_KEY });
509
+ await clearStagingRoot();
510
+ return;
511
+ }
512
+ };
364
513
  var installationId = async () => {
365
514
  const existing = await Preferences.get({ key: INSTALLATION_KEY });
366
515
  if (existing.value && /^[a-f0-9-]{36}$/u.test(existing.value))
@@ -379,6 +528,7 @@ var webView = () => {
379
528
  };
380
529
  var currentServerBasePath = () => new Promise((resolve) => webView().getServerBasePath(resolve));
381
530
  var releasePath = (releaseId) => `${ROOT}/${releaseId}`;
531
+ var partialPath = (releaseId, file) => `${STAGING_ROOT}/${releaseId}/${file.path}.part`;
382
532
  var releaseNativePath = async (releaseId) => {
383
533
  const { uri } = await Filesystem.getUri({
384
534
  directory: Directory.Library,
@@ -396,6 +546,15 @@ var removeRelease = async (releaseId) => {
396
546
  return;
397
547
  });
398
548
  };
549
+ var removeStaging = async (releaseId) => {
550
+ await Filesystem.rmdir({
551
+ directory: Directory.Library,
552
+ path: `${STAGING_ROOT}/${releaseId}`,
553
+ recursive: true
554
+ }).catch(() => {
555
+ return;
556
+ });
557
+ };
399
558
  var filesystemBytes = async (data) => typeof data === "string" ? base64Bytes(data) : new Uint8Array(await data.arrayBuffer());
400
559
  var createStore = () => {
401
560
  let staging;
@@ -403,6 +562,10 @@ var createStore = () => {
403
562
  abort: async (releaseId) => {
404
563
  staging = undefined;
405
564
  await removeRelease(releaseId);
565
+ await removeStaging(releaseId);
566
+ const persisted = await readStaging();
567
+ if (persisted?.releaseId === releaseId)
568
+ await Preferences.remove({ key: STAGING_KEY });
406
569
  const state = await readState();
407
570
  if (state.readyRelease === releaseId || state.pendingRelease === releaseId)
408
571
  await writeState({
@@ -439,18 +602,59 @@ var createStore = () => {
439
602
  throw error;
440
603
  }
441
604
  },
605
+ appendPartial: async (file, contents, offset) => {
606
+ if (!staging || !staging.files.some((candidate) => candidate.path === file.path))
607
+ throw new TypeError("Mobile update partial write is outside its staging transaction.");
608
+ const path = partialPath(staging.releaseId, file);
609
+ if (offset === 0) {
610
+ await Filesystem.writeFile({
611
+ data: bytesBase64(contents),
612
+ directory: Directory.Library,
613
+ path,
614
+ recursive: true
615
+ });
616
+ return;
617
+ }
618
+ const stat = await Filesystem.stat({
619
+ directory: Directory.Library,
620
+ path
621
+ });
622
+ if (stat.size !== offset)
623
+ throw new TypeError("Mobile update partial checkpoint changed unexpectedly.");
624
+ await Filesystem.appendFile({
625
+ data: bytesBase64(contents),
626
+ directory: Directory.Library,
627
+ path
628
+ });
629
+ },
442
630
  begin: async (manifest) => {
443
- await removeRelease(manifest.releaseId);
631
+ const persisted = await readStaging();
632
+ const resume = persisted?.releaseId === manifest.releaseId && persisted.signature.keyId === manifest.signature.keyId && persisted.signature.value === manifest.signature.value;
633
+ if (persisted && !resume)
634
+ await Promise.all([
635
+ removeRelease(persisted.releaseId),
636
+ removeStaging(persisted.releaseId)
637
+ ]);
638
+ if (!resume) {
639
+ await removeRelease(manifest.releaseId);
640
+ await removeStaging(manifest.releaseId);
641
+ }
444
642
  await Filesystem.mkdir({
445
643
  directory: Directory.Library,
446
644
  path: releasePath(manifest.releaseId),
447
645
  recursive: true
448
646
  });
647
+ await Preferences.set({
648
+ key: STAGING_KEY,
649
+ value: JSON.stringify(manifest)
650
+ });
449
651
  staging = manifest;
450
652
  },
451
653
  commit: async (manifest) => {
452
654
  if (staging?.releaseId !== manifest.releaseId)
453
655
  throw new TypeError("Mobile update staging transaction changed identity.");
656
+ await removeStaging(manifest.releaseId);
657
+ await Preferences.remove({ key: STAGING_KEY });
454
658
  const state = await readState();
455
659
  await writeState({
456
660
  activeRelease: state.activeRelease,
@@ -459,6 +663,15 @@ var createStore = () => {
459
663
  });
460
664
  staging = undefined;
461
665
  },
666
+ readPartial: async (file) => {
667
+ if (!staging)
668
+ return null;
669
+ const result = await Filesystem.readFile({
670
+ directory: Directory.Library,
671
+ path: partialPath(staging.releaseId, file)
672
+ }).catch(() => null);
673
+ return result ? filesystemBytes(result.data).catch(() => null) : null;
674
+ },
462
675
  readReusable: async (file) => {
463
676
  const state = await readState();
464
677
  if (!state.activeRelease)
@@ -469,6 +682,19 @@ var createStore = () => {
469
682
  }).catch(() => null);
470
683
  return result ? filesystemBytes(result.data).catch(() => null) : null;
471
684
  },
685
+ readStaged: async (file) => {
686
+ if (!staging)
687
+ return null;
688
+ const result = await Filesystem.readFile({
689
+ directory: Directory.Library,
690
+ path: `${releasePath(staging.releaseId)}/${file.path}`
691
+ }).catch(() => null);
692
+ return result ? filesystemBytes(result.data).catch(() => null) : null;
693
+ },
694
+ suspend: async (releaseId) => {
695
+ if (staging?.releaseId === releaseId)
696
+ staging = undefined;
697
+ },
472
698
  write: async (file, contents) => {
473
699
  if (!staging || !staging.files.some((candidate) => candidate.path === file.path))
474
700
  throw new TypeError("Mobile update write is outside its staging transaction.");
@@ -561,18 +787,25 @@ var installAbsoluteMobileShellUpdates = async (manifest) => {
561
787
  runtimeFingerprint: manifest.nativeRuntime
562
788
  },
563
789
  store,
564
- verifier: createVerifier(manifest.updates.publicKeys)
790
+ verifier: createVerifier(manifest.updates.publicKeys),
791
+ onProgress: (progress) => emitUpdateResult(progress)
565
792
  });
566
793
  const activateDownloaded = async (result) => {
567
794
  if (result.kind !== "downloaded")
568
795
  return;
569
796
  emitUpdateResult({
797
+ avoidedBytes: result.transfer.avoidedBytes,
798
+ completedFiles: result.transfer.completedFiles,
570
799
  downloadedBytes: result.transfer.downloadedBytes,
571
800
  downloadedFiles: result.transfer.downloadedFiles,
801
+ durationMs: Math.round(result.transfer.durationMs),
572
802
  kind: "downloaded",
573
803
  releaseId: result.manifest.releaseId,
804
+ resumedBytes: result.transfer.resumedBytes,
805
+ resumedFiles: result.transfer.resumedFiles,
574
806
  reusedBytes: result.transfer.reusedBytes,
575
807
  reusedFiles: result.transfer.reusedFiles,
808
+ throughputBytesPerSecond: result.transfer.throughputBytesPerSecond,
576
809
  totalBytes: result.transfer.totalBytes,
577
810
  totalFiles: result.transfer.totalFiles
578
811
  });
@@ -13,8 +13,16 @@ export type AbsoluteMobileUpdateStore = {
13
13
  activate(releaseId: string): Promise<void>;
14
14
  begin(manifest: AbsoluteMobileUpdateManifest): Promise<void>;
15
15
  commit(manifest: AbsoluteMobileUpdateManifest): Promise<void>;
16
+ /** Append a response chunk to persistent staging at the expected offset. */
17
+ appendPartial?(file: AbsoluteMobileUpdateFile, contents: Uint8Array, offset: number): Promise<void>;
18
+ /** Return an unverified, incomplete download from persistent staging. */
19
+ readPartial?(file: AbsoluteMobileUpdateFile): Promise<Uint8Array | null>;
16
20
  /** Return a locally cached candidate for this exact path, when available. */
17
21
  readReusable?(file: AbsoluteMobileUpdateFile): Promise<Uint8Array | null>;
22
+ /** Return an unverified completed file from a prior staging attempt. */
23
+ readStaged?(file: AbsoluteMobileUpdateFile): Promise<Uint8Array | null>;
24
+ /** End this attempt without deleting persistent staging. */
25
+ suspend?(releaseId: string): Promise<void>;
18
26
  write(file: AbsoluteMobileUpdateFile, contents: Uint8Array): Promise<void>;
19
27
  };
20
28
  export type AbsoluteMobileUpdateVerifier = {
@@ -23,7 +31,10 @@ export type AbsoluteMobileUpdateVerifier = {
23
31
  };
24
32
  export type AbsoluteMobileUpdateClientOptions = {
25
33
  config: AbsoluteMobileUpdateClientConfig;
34
+ /** Maximum parallel asset requests. Network conditions may reduce this. */
35
+ concurrency?: number;
26
36
  fetch?: typeof globalThis.fetch;
37
+ onProgress?: (progress: AbsoluteMobileUpdateProgress) => void;
27
38
  store: AbsoluteMobileUpdateStore;
28
39
  verifier: AbsoluteMobileUpdateVerifier;
29
40
  };
@@ -41,13 +52,22 @@ export type AbsoluteMobileUpdateCheckResult = {
41
52
  manifest: AbsoluteMobileUpdateManifest;
42
53
  };
43
54
  export type AbsoluteMobileUpdateTransfer = {
55
+ avoidedBytes: number;
56
+ completedFiles: number;
44
57
  downloadedBytes: number;
45
58
  downloadedFiles: number;
59
+ durationMs: number;
60
+ resumedBytes: number;
61
+ resumedFiles: number;
46
62
  reusedBytes: number;
47
63
  reusedFiles: number;
64
+ throughputBytesPerSecond: number;
48
65
  totalBytes: number;
49
66
  totalFiles: number;
50
67
  };
68
+ export type AbsoluteMobileUpdateProgress = AbsoluteMobileUpdateTransfer & {
69
+ kind: 'download-progress';
70
+ };
51
71
  export declare const createAbsoluteMobileUpdateClient: (options: AbsoluteMobileUpdateClientOptions) => {
52
72
  check: (download?: boolean) => Promise<AbsoluteMobileUpdateCheckResult>;
53
73
  activate: (releaseId: string) => Promise<void>;
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "dependencies": {
10
10
  "@absolutejs/auth": ">=0.75.0 <0.77.0",
11
11
  "@absolutejs/beacon": ">=0.7.0-beta.4 <0.8.0",
12
- "@absolutejs/deploy": "0.25.8",
12
+ "@absolutejs/deploy": "0.25.9",
13
13
  "@absolutejs/devices": "0.7.0",
14
14
  "@absolutejs/devices-capacitor": "0.8.0",
15
15
  "@absolutejs/devices-expo": "0.0.2",
@@ -523,7 +523,7 @@
523
523
  ]
524
524
  }
525
525
  },
526
- "version": "0.20.0-beta.84",
526
+ "version": "0.20.0-beta.85",
527
527
  "workspaces": [
528
528
  "tests/fixtures/*",
529
529
  "tests/fixtures/_packages/*"