expo-updates 0.19.0 → 0.20.0

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 (64) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/android/build.gradle +11 -8
  3. package/android/src/main/java/expo/modules/updates/UpdatesController.kt +2 -2
  4. package/android/src/main/java/expo/modules/updates/UpdatesDevLauncherController.kt +1 -1
  5. package/android/src/main/java/expo/modules/updates/UpdatesModule.kt +6 -7
  6. package/android/src/main/java/expo/modules/updates/db/UpdatesDatabase.kt +22 -1
  7. package/android/src/main/java/expo/modules/updates/db/entity/UpdateEntity.kt +2 -4
  8. package/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt +3 -2
  9. package/android/src/main/java/expo/modules/updates/manifest/BareUpdateManifest.kt +1 -1
  10. package/android/src/main/java/expo/modules/updates/manifest/LegacyUpdateManifest.kt +1 -2
  11. package/android/src/main/java/expo/modules/updates/manifest/NewUpdateManifest.kt +1 -3
  12. package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicies.kt +2 -3
  13. package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateContext.kt +12 -3
  14. package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateContextRollback.kt +14 -0
  15. package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateEvent.kt +2 -1
  16. package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateMachine.kt +5 -4
  17. package/build/Updates.d.ts +15 -12
  18. package/build/Updates.d.ts.map +1 -1
  19. package/build/Updates.js +28 -18
  20. package/build/Updates.js.map +1 -1
  21. package/build/Updates.types.d.ts +9 -10
  22. package/build/Updates.types.d.ts.map +1 -1
  23. package/build/Updates.types.js.map +1 -1
  24. package/build/UpdatesEmitter.d.ts.map +1 -1
  25. package/build/UpdatesEmitter.js +9 -19
  26. package/build/UpdatesEmitter.js.map +1 -1
  27. package/build/UseUpdates.types.d.ts +34 -3
  28. package/build/UseUpdates.types.d.ts.map +1 -1
  29. package/build/UseUpdates.types.js +4 -0
  30. package/build/UseUpdates.types.js.map +1 -1
  31. package/build/UseUpdatesUtils.d.ts +2 -1
  32. package/build/UseUpdatesUtils.d.ts.map +1 -1
  33. package/build/UseUpdatesUtils.js +15 -7
  34. package/build/UseUpdatesUtils.js.map +1 -1
  35. package/build/statemachine/UpdatesStateMachine.d.ts +1 -1
  36. package/build/statemachine/UpdatesStateMachine.js.map +1 -1
  37. package/e2e/fixtures/App-apitest.tsx +5 -3
  38. package/e2e/fixtures/App.tsx +5 -5
  39. package/e2e/fixtures/Updates.e2e.ts +8 -1
  40. package/expo-updates-gradle-plugin/src/main/kotlin/expo/modules/updates/ExpoUpdatesPlugin.kt +7 -2
  41. package/ios/EXUpdates/AppController.swift +2 -2
  42. package/ios/EXUpdates/AppLoader/AppLoaderTask.swift +7 -3
  43. package/ios/EXUpdates/AppLoader/UpdateResponse.swift +5 -0
  44. package/ios/EXUpdates/Database/Migrations/UpdatesDatabaseMigration9To10.swift +51 -0
  45. package/ios/EXUpdates/Database/Migrations/UpdatesDatabaseMigrationRegistry.swift +2 -1
  46. package/ios/EXUpdates/Database/UpdatesDatabase.swift +3 -7
  47. package/ios/EXUpdates/Database/UpdatesDatabaseInitialization.swift +9 -2
  48. package/ios/EXUpdates/UpdatesModule.swift +1 -1
  49. package/ios/EXUpdates/UpdatesStateMachine.swift +42 -13
  50. package/ios/EXUpdates/UpdatesUtils.swift +5 -1
  51. package/ios/Tests/DatabaseInitializationSpec.swift +120 -3
  52. package/ios/Tests/UpdatesStateMachineSpec.swift +3 -3
  53. package/package.json +8 -8
  54. package/plugin/build/withUpdates.d.ts +1 -3
  55. package/plugin/build/withUpdates.js +3 -6
  56. package/plugin/src/withUpdates.ts +3 -7
  57. package/scripts/createManifest.js +9 -3
  58. package/src/Updates.ts +29 -18
  59. package/src/Updates.types.ts +12 -17
  60. package/src/UpdatesEmitter.ts +9 -22
  61. package/src/UseUpdates.types.ts +34 -2
  62. package/src/UseUpdatesUtils.ts +18 -3
  63. package/src/statemachine/UpdatesStateMachine.ts +1 -1
  64. package/tsconfig.json +1 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,31 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.20.0 — 2023-09-04
14
+
15
+ ### 🛠 Breaking changes
16
+
17
+ - Change source of truth for constants types. ([#24049](https://github.com/expo/expo/pull/24049) by [@wschurman](https://github.com/wschurman))
18
+ - Remove classic manifest types and classic updates. ([#24053](https://github.com/expo/expo/pull/24053), [#24066](https://github.com/expo/expo/pull/24066) by [@wschurman](https://github.com/wschurman))
19
+
20
+ ### 🎉 New features
21
+
22
+ - Added support for React Native 0.73. ([#24018](https://github.com/expo/expo/pull/24018) by [@kudo](https://github.com/kudo))
23
+ - Add rollback support to useUpdates(). ([#24071](https://github.com/expo/expo/pull/24071) by [@douglowder](https://github.com/douglowder))
24
+
25
+ ### 🐛 Bug fixes
26
+
27
+ - [Android] completely fix `node` execution on Windows ([#24116](https://github.com/expo/expo/pull/24116) by [@weykon](https://github.com/weykon))
28
+ - [Android] Fixed the `node` execution on Windows. ([#23983](https://github.com/expo/expo/pull/23983) by [@kudo](https://github.com/kudo))
29
+ - Bare update manifest non-nullability parity. ([#23166](https://github.com/expo/expo/pull/23166) by [@wschurman](https://github.com/wschurman))
30
+ - Support importing assets from out of the project root when working in monorepos. ([#24090](https://github.com/expo/expo/pull/24090) by [@EvanBacon](https://github.com/EvanBacon))
31
+
32
+ ## 0.19.1 — 2023-08-02
33
+
34
+ ### 💡 Others
35
+
36
+ - Update API documentation to clarify `channel` behavior in Expo Go/ development builds. ([#23783](https://github.com/expo/expo/pull/23783) by [@keith-kurak](https://github.com/keith-kurak))
37
+
13
38
  ## 0.19.0 — 2023-07-28
14
39
 
15
40
  ### 🎉 New features
@@ -248,6 +273,7 @@ _This version does not introduce any user-facing changes._
248
273
 
249
274
  ### 🛠 Breaking changes
250
275
 
276
+ - Drop support for `logUrl` which sent console logs to the legacy `expo-cli`. ([#18596](https://github.com/expo/expo/pull/18596) by [@EvanBacon](https://github.com/EvanBacon))
251
277
  - [plugin] Upgrade minimum runtime requirement to Node 14 (LTS). ([#18204](https://github.com/expo/expo/pull/18204) by [@EvanBacon](https://github.com/EvanBacon))
252
278
  - Bumped iOS deployment target to 13.0 and deprecated support for iOS 12. ([#18873](https://github.com/expo/expo/pull/18873) by [@tsapeta](https://github.com/tsapeta))
253
279
 
@@ -4,7 +4,7 @@ apply plugin: 'kotlin-kapt'
4
4
  apply plugin: 'maven-publish'
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '0.19.0'
7
+ version = '0.20.0'
8
8
 
9
9
  // Utility method to derive boolean values from the environment or from Java properties,
10
10
  // and return them as strings to be used in BuildConfig fields
@@ -81,13 +81,16 @@ afterEvaluate {
81
81
  android {
82
82
  compileSdkVersion safeExtGet("compileSdkVersion", 33)
83
83
 
84
- compileOptions {
85
- sourceCompatibility JavaVersion.VERSION_11
86
- targetCompatibility JavaVersion.VERSION_11
87
- }
84
+ def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
85
+ if (agpVersion.tokenize('.')[0].toInteger() < 8) {
86
+ compileOptions {
87
+ sourceCompatibility JavaVersion.VERSION_11
88
+ targetCompatibility JavaVersion.VERSION_11
89
+ }
88
90
 
89
- kotlinOptions {
90
- jvmTarget = JavaVersion.VERSION_11.majorVersion
91
+ kotlinOptions {
92
+ jvmTarget = JavaVersion.VERSION_11.majorVersion
93
+ }
91
94
  }
92
95
 
93
96
  namespace "expo.modules.updates"
@@ -95,7 +98,7 @@ android {
95
98
  minSdkVersion safeExtGet("minSdkVersion", 21)
96
99
  targetSdkVersion safeExtGet("targetSdkVersion", 33)
97
100
  versionCode 31
98
- versionName '0.19.0'
101
+ versionName '0.20.0'
99
102
  consumerProguardFiles("proguard-rules.pro")
100
103
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
101
104
 
@@ -289,7 +289,7 @@ class UpdatesController private constructor(
289
289
  val event = when (result) {
290
290
  is LoaderTask.RemoteCheckResult.NoUpdateAvailable -> UpdatesStateEvent.CheckCompleteUnavailable()
291
291
  is LoaderTask.RemoteCheckResult.UpdateAvailable -> UpdatesStateEvent.CheckCompleteWithUpdate(result.manifest)
292
- is LoaderTask.RemoteCheckResult.RollBackToEmbedded -> UpdatesStateEvent.CheckCompleteWithRollback()
292
+ is LoaderTask.RemoteCheckResult.RollBackToEmbedded -> UpdatesStateEvent.CheckCompleteWithRollback(result.commitTime)
293
293
  }
294
294
  stateMachine.processEvent(event)
295
295
  }
@@ -375,7 +375,7 @@ class UpdatesController private constructor(
375
375
  params.putString("manifestString", update.manifest.toString())
376
376
  sendLegacyUpdateEventToJS(UPDATE_AVAILABLE_EVENT, params)
377
377
  stateMachine.processEvent(
378
- UpdatesStateEvent.DownloadCompleteWithUpdate(update.manifest!!)
378
+ UpdatesStateEvent.DownloadCompleteWithUpdate(update.manifest)
379
379
  )
380
380
  }
381
381
  RemoteUpdateStatus.NO_UPDATE_AVAILABLE -> {
@@ -154,7 +154,7 @@ class UpdatesDevLauncherController : UpdatesInterface {
154
154
  controller.setLauncher(launcher)
155
155
  callback.onSuccess(object : UpdatesInterface.Update {
156
156
  override fun getManifest(): JSONObject {
157
- return launcher.launchedUpdate!!.manifest!!
157
+ return launcher.launchedUpdate!!.manifest
158
158
  }
159
159
 
160
160
  override fun getLaunchAssetPath(): String {
@@ -80,8 +80,7 @@ class UpdatesModule(
80
80
  if (launchedUpdate != null) {
81
81
  constants["updateId"] = launchedUpdate.id.toString()
82
82
  constants["commitTime"] = launchedUpdate.commitTime.time
83
- constants["manifestString"] =
84
- if (launchedUpdate.manifest != null) launchedUpdate.manifest.toString() else "{}"
83
+ constants["manifestString"] = launchedUpdate.manifest.toString()
85
84
  }
86
85
  val localAssetFiles = updatesServiceLocal.localAssetFiles
87
86
  if (localAssetFiles != null) {
@@ -138,7 +137,7 @@ class UpdatesModule(
138
137
  }
139
138
  }
140
139
 
141
- // Used internally by @expo/use-updates useUpdates() to get its initial state
140
+ // Used internally by useUpdates() to get its initial state
142
141
  @ExpoMethod
143
142
  fun getNativeStateMachineContextAsync(promise: Promise) {
144
143
  try {
@@ -221,7 +220,7 @@ class UpdatesModule(
221
220
  return
222
221
  }
223
222
 
224
- promise.resolveWithCheckForUpdateAsyncResult(CheckForUpdateAsyncResult.RollBackToEmbedded(), updatesServiceLocal)
223
+ promise.resolveWithCheckForUpdateAsyncResult(CheckForUpdateAsyncResult.RollBackToEmbedded(updateDirective.commitTime), updatesServiceLocal)
225
224
  return
226
225
  }
227
226
  }
@@ -269,7 +268,7 @@ class UpdatesModule(
269
268
 
270
269
  class NoUpdateAvailable : CheckForUpdateAsyncResult(Status.NO_UPDATE_AVAILABLE)
271
270
  class UpdateAvailable(val updateManifest: UpdateManifest) : CheckForUpdateAsyncResult(Status.UPDATE_AVAILABLE)
272
- class RollBackToEmbedded : CheckForUpdateAsyncResult(Status.ROLL_BACK_TO_EMBEDDED)
271
+ class RollBackToEmbedded(val commitTime: Date) : CheckForUpdateAsyncResult(Status.ROLL_BACK_TO_EMBEDDED)
273
272
  }
274
273
 
275
274
  private fun Promise.resolveWithCheckForUpdateAsyncResult(checkForUpdateAsyncResult: CheckForUpdateAsyncResult, updatesServiceLocal: UpdatesInterface) {
@@ -297,7 +296,7 @@ class UpdatesModule(
297
296
  updatesServiceLocal.stateMachine?.processEvent(
298
297
  when (checkForUpdateAsyncResult) {
299
298
  is CheckForUpdateAsyncResult.NoUpdateAvailable -> UpdatesStateEvent.CheckCompleteUnavailable()
300
- is CheckForUpdateAsyncResult.RollBackToEmbedded -> UpdatesStateEvent.CheckCompleteWithRollback()
299
+ is CheckForUpdateAsyncResult.RollBackToEmbedded -> UpdatesStateEvent.CheckCompleteWithRollback(checkForUpdateAsyncResult.commitTime)
301
300
  is CheckForUpdateAsyncResult.UpdateAvailable -> UpdatesStateEvent.CheckCompleteWithUpdate(
302
301
  checkForUpdateAsyncResult.updateManifest.manifest.getRawJson()
303
302
  )
@@ -418,7 +417,7 @@ class UpdatesModule(
418
417
  }
419
418
  )
420
419
  updatesServiceLocal.stateMachine?.processEvent(
421
- UpdatesStateEvent.DownloadCompleteWithUpdate(updateEntity.manifest!!)
420
+ UpdatesStateEvent.DownloadCompleteWithUpdate(updateEntity.manifest)
422
421
  )
423
422
  }
424
423
  }
@@ -44,7 +44,7 @@ import java.util.*
44
44
  @Database(
45
45
  entities = [UpdateEntity::class, UpdateAssetEntity::class, AssetEntity::class, JSONDataEntity::class],
46
46
  exportSchema = false,
47
- version = 11
47
+ version = 12
48
48
  )
49
49
  @TypeConverters(Converters::class)
50
50
  abstract class UpdatesDatabase : RoomDatabase() {
@@ -69,6 +69,7 @@ abstract class UpdatesDatabase : RoomDatabase() {
69
69
  .addMigrations(MIGRATION_8_9)
70
70
  .addMigrations(MIGRATION_9_10)
71
71
  .addMigrations(MIGRATION_10_11)
72
+ .addMigrations(MIGRATION_11_12)
72
73
  .fallbackToDestructiveMigration()
73
74
  .allowMainThreadQueries()
74
75
  .build()
@@ -199,5 +200,25 @@ abstract class UpdatesDatabase : RoomDatabase() {
199
200
  }
200
201
  }
201
202
  }
203
+
204
+ /**
205
+ * Change the `updates.manifest` column to be non-null
206
+ */
207
+ val MIGRATION_11_12: Migration = object : Migration(11, 12) {
208
+ override fun migrate(database: SupportSQLiteDatabase) {
209
+ database.runInTransactionWithForeignKeysOff {
210
+ execSQL("CREATE TABLE `new_updates` (`id` BLOB NOT NULL, `scope_key` TEXT NOT NULL, `commit_time` INTEGER NOT NULL, `runtime_version` TEXT NOT NULL, `launch_asset_id` INTEGER, `manifest` TEXT NOT NULL, `status` INTEGER NOT NULL, `keep` INTEGER NOT NULL, `last_accessed` INTEGER NOT NULL, `successful_launch_count` INTEGER NOT NULL DEFAULT 0, `failed_launch_count` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`id`), FOREIGN KEY(`launch_asset_id`) REFERENCES `assets`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
211
+
212
+ execSQL(
213
+ "INSERT INTO `new_updates` (`id`, `scope_key`, `commit_time`, `runtime_version`, `launch_asset_id`, `manifest`, `status`, `keep`, `last_accessed`, `successful_launch_count`, `failed_launch_count`)" +
214
+ " SELECT `id`, `scope_key`, `commit_time`, `runtime_version`, `launch_asset_id`, `manifest`, `status`, `keep`, `last_accessed`, `successful_launch_count`, `failed_launch_count` FROM `updates` WHERE `manifest` IS NOT NULL"
215
+ )
216
+ execSQL("DROP TABLE `updates`")
217
+ execSQL("ALTER TABLE `new_updates` RENAME TO `updates`")
218
+ execSQL("CREATE INDEX `index_updates_launch_asset_id` ON `updates` (`launch_asset_id`)")
219
+ execSQL("CREATE UNIQUE INDEX `index_updates_scope_key_commit_time` ON `updates` (`scope_key`, `commit_time`)")
220
+ }
221
+ }
222
+ }
202
223
  }
203
224
  }
@@ -36,14 +36,12 @@ class UpdateEntity(
36
36
  @field:ColumnInfo(typeAffinity = ColumnInfo.BLOB) @field:PrimaryKey var id: UUID,
37
37
  @field:ColumnInfo(name = "commit_time") var commitTime: Date,
38
38
  @field:ColumnInfo(name = "runtime_version") var runtimeVersion: String,
39
- @field:ColumnInfo(name = "scope_key") var scopeKey: String
39
+ @field:ColumnInfo(name = "scope_key") var scopeKey: String,
40
+ @field:ColumnInfo(name = "manifest") var manifest: JSONObject,
40
41
  ) {
41
42
  @ColumnInfo(name = "launch_asset_id")
42
43
  var launchAssetId: Long? = null
43
44
 
44
- @ColumnInfo(name = "manifest")
45
- var manifest: JSONObject? = null
46
-
47
45
  var status = UpdateStatus.PENDING
48
46
 
49
47
  var keep = false
@@ -21,6 +21,7 @@ import expo.modules.updates.manifest.UpdateManifest
21
21
  import expo.modules.updates.selectionpolicy.SelectionPolicy
22
22
  import org.json.JSONObject
23
23
  import java.io.File
24
+ import java.util.Date
24
25
 
25
26
  /**
26
27
  * Controlling class that handles the complex logic that needs to happen each time the app is cold
@@ -62,7 +63,7 @@ class LoaderTask(
62
63
 
63
64
  class NoUpdateAvailable : RemoteCheckResult(Status.NO_UPDATE_AVAILABLE)
64
65
  class UpdateAvailable(val manifest: JSONObject) : RemoteCheckResult(Status.UPDATE_AVAILABLE)
65
- class RollBackToEmbedded : RemoteCheckResult(Status.ROLL_BACK_TO_EMBEDDED)
66
+ class RollBackToEmbedded(val commitTime: Date) : RemoteCheckResult(Status.ROLL_BACK_TO_EMBEDDED)
66
67
  }
67
68
 
68
69
  interface LoaderTaskCallback {
@@ -335,7 +336,7 @@ class LoaderTask(
335
336
  return when (updateDirective) {
336
337
  is UpdateDirective.RollBackToEmbeddedUpdateDirective -> {
337
338
  isUpToDate = true
338
- callback.onRemoteCheckForUpdateFinished(RemoteCheckResult.RollBackToEmbedded())
339
+ callback.onRemoteCheckForUpdateFinished(RemoteCheckResult.RollBackToEmbedded(updateDirective.commitTime))
339
340
  Loader.OnUpdateResponseLoadedResult(shouldDownloadManifestIfPresentInResponse = false)
340
341
  }
341
342
  is UpdateDirective.NoUpdateAvailableUpdateDirective -> {
@@ -28,7 +28,7 @@ class BareUpdateManifest private constructor(
28
28
  private val mAssets: JSONArray?
29
29
  ) : UpdateManifest {
30
30
  override val updateEntity: UpdateEntity by lazy {
31
- UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey).apply {
31
+ UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey, this@BareUpdateManifest.manifest.getRawJson()).apply {
32
32
  status = UpdateStatus.EMBEDDED
33
33
  }
34
34
  }
@@ -34,8 +34,7 @@ class LegacyUpdateManifest private constructor(
34
34
  private val mAssets: JSONArray?
35
35
  ) : UpdateManifest {
36
36
  override val updateEntity: UpdateEntity by lazy {
37
- UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey).apply {
38
- manifest = this@LegacyUpdateManifest.manifest.getRawJson()
37
+ UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey, this@LegacyUpdateManifest.manifest.getRawJson()).apply {
39
38
  if (isDevelopmentMode) {
40
39
  status = UpdateStatus.DEVELOPMENT
41
40
  }
@@ -31,9 +31,7 @@ class NewUpdateManifest private constructor(
31
31
  private val mExtensions: JSONObject?
32
32
  ) : UpdateManifest {
33
33
  override val updateEntity: UpdateEntity by lazy {
34
- UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey).apply {
35
- manifest = this@NewUpdateManifest.manifest.getRawJson()
36
- }
34
+ UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey, this@NewUpdateManifest.manifest.getRawJson())
37
35
  }
38
36
 
39
37
  private val assetHeaders: Map<String, JSONObject> by lazy {
@@ -13,13 +13,12 @@ object SelectionPolicies {
13
13
  val TAG = SelectionPolicies::class.java.simpleName
14
14
 
15
15
  fun matchesFilters(update: UpdateEntity, manifestFilters: JSONObject?): Boolean {
16
- val rawManifest = update.manifest
17
- if (manifestFilters == null || rawManifest == null) {
16
+ if (manifestFilters == null) {
18
17
  // empty matches all
19
18
  return true
20
19
  }
21
20
 
22
- val manifest = Manifest.fromManifestJson(rawManifest)
21
+ val manifest = Manifest.fromManifestJson(update.manifest)
23
22
  val metadata = manifest.getMetadata() ?: return true // empty matches all
24
23
 
25
24
  try {
@@ -14,12 +14,12 @@ The state machine context, with information intended to be consumed by applicati
14
14
  data class UpdatesStateContext(
15
15
  val isUpdateAvailable: Boolean = false,
16
16
  val isUpdatePending: Boolean = false,
17
- val isRollback: Boolean = false,
18
17
  val isChecking: Boolean = false,
19
18
  val isDownloading: Boolean = false,
20
19
  val isRestarting: Boolean = false,
21
20
  val latestManifest: JSONObject? = null,
22
21
  val downloadedManifest: JSONObject? = null,
22
+ val rollback: UpdatesStateContextRollback? = null,
23
23
  val checkError: UpdatesStateError? = null,
24
24
  val downloadError: UpdatesStateError? = null,
25
25
  val lastCheckForUpdateTime: Date? = null,
@@ -30,7 +30,6 @@ data class UpdatesStateContext(
30
30
  val map: MutableMap<String, Any> = mutableMapOf(
31
31
  "isUpdateAvailable" to isUpdateAvailable,
32
32
  "isUpdatePending" to isUpdatePending,
33
- "isRollback" to isRollback,
34
33
  "isChecking" to isChecking,
35
34
  "isDownloading" to isDownloading,
36
35
  "isRestarting" to isRestarting
@@ -41,6 +40,9 @@ data class UpdatesStateContext(
41
40
  if (downloadedManifest != null) {
42
41
  map["downloadedManifest"] = downloadedManifest
43
42
  }
43
+ if (rollback != null) {
44
+ map["rollback"] = rollback.json
45
+ }
44
46
  if (checkError != null) {
45
47
  map["checkError"] = checkError.json
46
48
  }
@@ -71,7 +73,6 @@ data class UpdatesStateContext(
71
73
  return Bundle().apply {
72
74
  putBoolean("isUpdateAvailable", isUpdateAvailable)
73
75
  putBoolean("isUpdatePending", isUpdatePending)
74
- putBoolean("isRollback", isRollback)
75
76
  putBoolean("isChecking", isChecking)
76
77
  putBoolean("isDownloading", isDownloading)
77
78
  putBoolean("isRestarting", isRestarting)
@@ -81,6 +82,14 @@ data class UpdatesStateContext(
81
82
  if (downloadedManifest != null) {
82
83
  putString("downloadedManifestString", downloadedManifest.toString())
83
84
  }
85
+ if (rollback != null) {
86
+ putBundle(
87
+ "rollback",
88
+ Bundle().apply {
89
+ putString("commitTime", rollback.commitTimeString)
90
+ }
91
+ )
92
+ }
84
93
  if (checkError != null) {
85
94
  val errorMap = Bundle().apply {
86
95
  putString("message", checkError.message)
@@ -0,0 +1,14 @@
1
+ package expo.modules.updates.statemachine
2
+
3
+ import java.util.Date
4
+
5
+ data class UpdatesStateContextRollback(
6
+ val commitTime: Date
7
+ ) {
8
+
9
+ val commitTimeString: String
10
+ get() = UpdatesStateContext.DATE_FORMATTER.format(commitTime)
11
+
12
+ val json: Map<String, Any>
13
+ get() = mapOf("commitTime" to commitTimeString)
14
+ }
@@ -1,6 +1,7 @@
1
1
  package expo.modules.updates.statemachine
2
2
 
3
3
  import org.json.JSONObject
4
+ import java.util.Date
4
5
 
5
6
  /**
6
7
  Structure representing an event that can be sent to the machine.
@@ -22,7 +23,7 @@ sealed class UpdatesStateEvent(val type: UpdatesStateEventType) {
22
23
  }
23
24
  class CheckCompleteUnavailable : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteUnavailable)
24
25
  class CheckCompleteWithUpdate(val manifest: JSONObject) : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteAvailable)
25
- class CheckCompleteWithRollback : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteAvailable)
26
+ class CheckCompleteWithRollback(val commitTime: Date) : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteAvailable)
26
27
  class DownloadComplete : UpdatesStateEvent(UpdatesStateEventType.DownloadComplete)
27
28
  class DownloadCompleteWithUpdate(val manifest: JSONObject) : UpdatesStateEvent(UpdatesStateEventType.DownloadComplete)
28
29
  class DownloadCompleteWithRollback : UpdatesStateEvent(UpdatesStateEventType.DownloadComplete)
@@ -106,24 +106,24 @@ class UpdatesStateMachine(
106
106
  isChecking = false,
107
107
  checkError = null,
108
108
  latestManifest = null,
109
+ rollback = null,
109
110
  isUpdateAvailable = false,
110
- isRollback = false,
111
111
  lastCheckForUpdateTime = Date(),
112
112
  )
113
113
  is UpdatesStateEvent.CheckCompleteWithRollback -> context.copy(
114
114
  isChecking = false,
115
115
  checkError = null,
116
116
  latestManifest = null,
117
+ rollback = UpdatesStateContextRollback(event.commitTime),
117
118
  isUpdateAvailable = true,
118
- isRollback = true,
119
119
  lastCheckForUpdateTime = Date()
120
120
  )
121
121
  is UpdatesStateEvent.CheckCompleteWithUpdate -> context.copy(
122
122
  isChecking = false,
123
123
  checkError = null,
124
124
  latestManifest = event.manifest,
125
+ rollback = null,
125
126
  isUpdateAvailable = true,
126
- isRollback = false,
127
127
  lastCheckForUpdateTime = Date()
128
128
  )
129
129
  is UpdatesStateEvent.CheckError -> context.copy(
@@ -140,13 +140,14 @@ class UpdatesStateMachine(
140
140
  is UpdatesStateEvent.DownloadCompleteWithRollback -> context.copy(
141
141
  isDownloading = false,
142
142
  downloadError = null,
143
- isUpdatePending = true,
143
+ isUpdatePending = true
144
144
  )
145
145
  is UpdatesStateEvent.DownloadCompleteWithUpdate -> context.copy(
146
146
  isDownloading = false,
147
147
  downloadError = null,
148
148
  latestManifest = event.manifest,
149
149
  downloadedManifest = event.manifest,
150
+ rollback = null,
150
151
  isUpdatePending = true,
151
152
  isUpdateAvailable = true
152
153
  )
@@ -1,9 +1,8 @@
1
1
  import { LocalAssets, Manifest, UpdateCheckResult, UpdateFetchResult, UpdatesCheckAutomaticallyValue, UpdatesLogEntry, UpdatesNativeStateMachineContext } from './Updates.types';
2
2
  /**
3
- * The UUID that uniquely identifies the currently running update if `expo-updates` is enabled. The
3
+ * The UUID that uniquely identifies the currently running update. The
4
4
  * UUID is represented in its canonical string form (`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) and
5
- * will always use lowercase letters. In development mode, or any other environment in which
6
- * `expo-updates` is disabled, this value is `null`.
5
+ * will always use lowercase letters. This value is `null` when running in a local development environment or any other environment where `expo-updates` is disabled.
7
6
  */
8
7
  export declare const updateId: string | null;
9
8
  /**
@@ -12,7 +11,9 @@ export declare const updateId: string | null;
12
11
  */
13
12
  export declare const releaseChannel: string;
14
13
  /**
15
- * The channel name of the current build, if configured for use with EAS Update. Null otherwise.
14
+ * The channel name of the current build, if configured for use with EAS Update. `null` otherwise.
15
+ *
16
+ * Expo Go and development builds are not set to a specific channel and can run any updates compatible with their native runtime. Therefore, this value will always be `null` when running an update on Expo Go or a development build.
16
17
  */
17
18
  export declare const channel: string | null;
18
19
  /**
@@ -112,14 +113,8 @@ export declare function getExtraParamsAsync(): Promise<{
112
113
  }>;
113
114
  /**
114
115
  * Sets an extra param if value is non-null, otherwise unsets the param.
115
- * Extra params are sent in a header of update requests.
116
- * The update server may use these params when evaluating logic to determine which update to serve.
117
- * EAS Update merges these params into the fields used to evaluate channel–branch mapping logic.
118
- *
119
- * @example An app may want to add a feature where users can opt-in to beta updates. In this instance,
120
- * extra params could be set to `{userType: 'beta'}`, and then the server can use this information
121
- * when deciding which update to serve. If using EAS Update, the channel-branch mapping can be set to
122
- * discriminate branches based on the `userType`.
116
+ * Extra params are sent as an [Expo Structured Field Value Dictionary](https://docs.expo.dev/technical-specs/expo-sfv-0/)
117
+ * in the `Expo-Extra-Params` header of update requests. A compliant update server may use these params when selecting an update to serve.
123
118
  */
124
119
  export declare function setExtraParamAsync(key: string, value: string | null | undefined): Promise<void>;
125
120
  /**
@@ -149,6 +144,10 @@ export declare function clearLogEntriesAsync(): Promise<void>;
149
144
  * storage. This method cannot be used in development mode, and the returned promise will be
150
145
  * rejected if you try to do so.
151
146
  *
147
+ > **Note:** [`reloadAsync()`](#updatesreloadasync) can be called after promise resolution to
148
+ * reload the app using the most recently downloaded version. Otherwise, the update will be applied
149
+ * on the next app cold start.
150
+ *
152
151
  * @return A promise that fulfills with an [`UpdateFetchResult`](#updatefetchresult) object.
153
152
  *
154
153
  * The promise rejects if the app is in development mode, or if there is an unexpected error or
@@ -159,6 +158,10 @@ export declare function fetchUpdateAsync(): Promise<UpdateFetchResult>;
159
158
  * @hidden
160
159
  */
161
160
  export declare function clearUpdateCacheExperimentalAsync(_sdkVersion?: string): void;
161
+ /**
162
+ * @hidden
163
+ */
164
+ export declare function transformNativeStateMachineContext(originalNativeContext: any): any;
162
165
  /**
163
166
  * @hidden
164
167
  */
@@ -1 +1 @@
1
- {"version":3,"file":"Updates.d.ts","sourceRoot":"","sources":["../src/Updates.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,EACX,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,8BAA8B,EAC9B,eAAe,EACf,gCAAgC,EACjC,MAAM,iBAAiB,CAAC;AAEzB;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,GAAG,IAGtB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,MAAgD,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,GAAG,IAAkC,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,GAAG,IAAyC,CAAC;AAShF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,8BAA8B,GAAG,IACQ,CAAC;AAG3E;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,WAA2C,CAAC;AAEtE;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAAgD,CAAC;AAEjF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAA+C,CAAC;AAG/E;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,OAAoD,CAAC;AAEzF;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAEnC,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,IAAI,GAAG,IAEvB,CAAC;AAUT;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAWjD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAkBtE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC,CAM9E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,GAAE,MAAgB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAK9F;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAK1D;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAkBnE;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAAC,WAAW,CAAC,EAAE,MAAM,QAIrE;AAED;;GAEG;AACH,wBAAsB,iCAAiC,IAAI,OAAO,CAAC,gCAAgC,CAAC,CAmBnG"}
1
+ {"version":3,"file":"Updates.d.ts","sourceRoot":"","sources":["../src/Updates.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,EACX,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,8BAA8B,EAC9B,eAAe,EACf,gCAAgC,EACjC,MAAM,iBAAiB,CAAC;AAEzB;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,GAAG,IAGtB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,MAAgD,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,GAAG,IAAkC,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,GAAG,IAAyC,CAAC;AAShF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,8BAA8B,GAAG,IACQ,CAAC;AAG3E;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,WAA2C,CAAC;AAEtE;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAAgD,CAAC;AAEjF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAA+C,CAAC;AAG/E;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,OAAoD,CAAC;AAEzF;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAEnC,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,IAAI,GAAG,IAEvB,CAAC;AAUT;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAWjD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAkBtE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC,CAM9E;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,GAAE,MAAgB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAK9F;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAK1D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAkBnE;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAAC,WAAW,CAAC,EAAE,MAAM,QAIrE;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAAC,qBAAqB,EAAE,GAAG,OAmB5E;AAED;;GAEG;AACH,wBAAsB,iCAAiC,IAAI,OAAO,CAAC,gCAAgC,CAAC,CAOnG"}
package/build/Updates.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import { CodedError, NativeModulesProxy, UnavailabilityError } from 'expo-modules-core';
2
2
  import ExpoUpdates from './ExpoUpdates';
3
3
  /**
4
- * The UUID that uniquely identifies the currently running update if `expo-updates` is enabled. The
4
+ * The UUID that uniquely identifies the currently running update. The
5
5
  * UUID is represented in its canonical string form (`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) and
6
- * will always use lowercase letters. In development mode, or any other environment in which
7
- * `expo-updates` is disabled, this value is `null`.
6
+ * will always use lowercase letters. This value is `null` when running in a local development environment or any other environment where `expo-updates` is disabled.
8
7
  */
9
8
  export const updateId = ExpoUpdates.updateId && typeof ExpoUpdates.updateId === 'string'
10
9
  ? ExpoUpdates.updateId.toLowerCase()
@@ -15,7 +14,9 @@ export const updateId = ExpoUpdates.updateId && typeof ExpoUpdates.updateId ===
15
14
  */
16
15
  export const releaseChannel = ExpoUpdates.releaseChannel ?? 'default';
17
16
  /**
18
- * The channel name of the current build, if configured for use with EAS Update. Null otherwise.
17
+ * The channel name of the current build, if configured for use with EAS Update. `null` otherwise.
18
+ *
19
+ * Expo Go and development builds are not set to a specific channel and can run any updates compatible with their native runtime. Therefore, this value will always be `null` when running an update on Expo Go or a development build.
19
20
  */
20
21
  export const channel = ExpoUpdates.channel ?? null;
21
22
  /**
@@ -157,14 +158,8 @@ export async function getExtraParamsAsync() {
157
158
  }
158
159
  /**
159
160
  * Sets an extra param if value is non-null, otherwise unsets the param.
160
- * Extra params are sent in a header of update requests.
161
- * The update server may use these params when evaluating logic to determine which update to serve.
162
- * EAS Update merges these params into the fields used to evaluate channel–branch mapping logic.
163
- *
164
- * @example An app may want to add a feature where users can opt-in to beta updates. In this instance,
165
- * extra params could be set to `{userType: 'beta'}`, and then the server can use this information
166
- * when deciding which update to serve. If using EAS Update, the channel-branch mapping can be set to
167
- * discriminate branches based on the `userType`.
161
+ * Extra params are sent as an [Expo Structured Field Value Dictionary](https://docs.expo.dev/technical-specs/expo-sfv-0/)
162
+ * in the `Expo-Extra-Params` header of update requests. A compliant update server may use these params when selecting an update to serve.
168
163
  */
169
164
  export async function setExtraParamAsync(key, value) {
170
165
  if (!ExpoUpdates.setExtraParamAsync) {
@@ -209,6 +204,10 @@ export async function clearLogEntriesAsync() {
209
204
  * storage. This method cannot be used in development mode, and the returned promise will be
210
205
  * rejected if you try to do so.
211
206
  *
207
+ > **Note:** [`reloadAsync()`](#updatesreloadasync) can be called after promise resolution to
208
+ * reload the app using the most recently downloaded version. Otherwise, the update will be applied
209
+ * on the next app cold start.
210
+ *
212
211
  * @return A promise that fulfills with an [`UpdateFetchResult`](#updatefetchresult) object.
213
212
  *
214
213
  * The promise rejects if the app is in development mode, or if there is an unexpected error or
@@ -237,12 +236,8 @@ export function clearUpdateCacheExperimentalAsync(_sdkVersion) {
237
236
  /**
238
237
  * @hidden
239
238
  */
240
- export async function getNativeStateMachineContextAsync() {
241
- // Return the current state machine context
242
- if (!ExpoUpdates.getNativeStateMachineContextAsync) {
243
- throw new UnavailabilityError('Updates', 'getNativeStateMachineContextAsync');
244
- }
245
- const nativeContext = await ExpoUpdates.getNativeStateMachineContextAsync();
239
+ export function transformNativeStateMachineContext(originalNativeContext) {
240
+ const nativeContext = { ...originalNativeContext };
246
241
  if (nativeContext.latestManifestString) {
247
242
  nativeContext.latestManifest = JSON.parse(nativeContext.latestManifestString);
248
243
  delete nativeContext.latestManifestString;
@@ -255,6 +250,21 @@ export async function getNativeStateMachineContextAsync() {
255
250
  nativeContext.lastCheckForUpdateTime = new Date(nativeContext.lastCheckForUpdateTimeString);
256
251
  delete nativeContext.lastCheckForUpdateTimeString;
257
252
  }
253
+ if (nativeContext.rollbackString) {
254
+ nativeContext.rollback = JSON.parse(nativeContext.rollbackString);
255
+ delete nativeContext.rollbackString;
256
+ }
258
257
  return nativeContext;
259
258
  }
259
+ /**
260
+ * @hidden
261
+ */
262
+ export async function getNativeStateMachineContextAsync() {
263
+ // Return the current state machine context
264
+ if (!ExpoUpdates.getNativeStateMachineContextAsync) {
265
+ throw new UnavailabilityError('Updates', 'getNativeStateMachineContextAsync');
266
+ }
267
+ const nativeContext = await ExpoUpdates.getNativeStateMachineContextAsync();
268
+ return transformNativeStateMachineContext(nativeContext);
269
+ }
260
270
  //# sourceMappingURL=Updates.js.map