Bug 1383622 (part 2) - update TPS to use the async bookmark API. r?tcsc draft
authorMark Hammond <mhammond@skippinet.com.au>
Tue, 15 Aug 2017 12:44:50 +1000
changeset 647816 c1e6d3efbf3075488f0ab1891b90efc9c0db7c96
parent 647789 1a9e739d894d2bbe2d99a6a73a2a5ff8ed41598e
child 726643 ee7986b5228ca28fa9533fbec52ce7d0a697212a
push id74551
push userbmo:markh@mozilla.com
push dateThu, 17 Aug 2017 00:16:03 +0000
reviewerstcsc
bugs1383622
milestone57.0a1
Bug 1383622 (part 2) - update TPS to use the async bookmark API. r?tcsc MozReview-Commit-ID: CnTx1stPyCY
services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm
services/sync/tps/extensions/tps/resource/tps.jsm
--- a/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm
+++ b/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm
@@ -14,27 +14,20 @@ const {classes: Cc, interfaces: Ci, util
 
 Cu.import("resource://gre/modules/PlacesBackups.jsm");
 Cu.import("resource://gre/modules/PlacesSyncUtils.jsm");
 Cu.import("resource://gre/modules/PlacesUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://tps/logger.jsm");
 
-var DumpBookmarks = function TPS_Bookmarks__DumpBookmarks() {
-  let cb = Async.makeSpinningCallback();
-  PlacesBackups.getBookmarksTree().then(result => {
-    let [bookmarks, ] = result;
-    Logger.logInfo("Dumping Bookmarks...\n" + JSON.stringify(bookmarks) + "\n\n");
-    cb(null);
-  }).catch(error => {
-    cb(error);
-  });
-  cb.wait();
-};
+async function DumpBookmarks() {
+  let [bookmarks, ] = await PlacesBackups.getBookmarksTree()
+  Logger.logInfo("Dumping Bookmarks...\n" + JSON.stringify(bookmarks, undefined, 2) + "\n\n");
+}
 
 /**
  * extend, causes a child object to inherit from a parent
  */
 function extend(child, supertype) {
    child.prototype.__proto__ = supertype.prototype;
 }
 
@@ -80,23 +73,29 @@ function PlacesItem(props) {
 }
 
 /**
  * Instance methods for generic places items.
  */
 PlacesItem.prototype = {
   // an array of possible root folders for places items
   _bookmarkFolders: {
-    "places": "placesRoot",
-    "menu": "bookmarksMenuFolder",
-    "tags": "tagFolder",
-    "unfiled": "unfiledBookmarksFolder",
-    "toolbar": "toolbarFolder",
+    "places": PlacesUtils.bookmarks.rootGuid,
+    "menu": PlacesUtils.bookmarks.menuGuid,
+    "tags": PlacesUtils.bookmarks.tagsGuid,
+    "unfiled": PlacesUtils.bookmarks.unfiledGuid,
+    "toolbar": PlacesUtils.bookmarks.toolbarGuid,
   },
 
+  _typeMap: new Map([
+    [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER, PlacesUtils.bookmarks.TYPE_FOLDER],
+    [PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR, PlacesUtils.bookmarks.TYPE_SEPARATOR],
+    [PlacesUtils.TYPE_X_MOZ_PLACE, PlacesUtils.bookmarks.TYPE_BOOKMARK],
+  ]),
+
   toString() {
     var that = this;
     var props = ["uri", "title", "location", "folder", "feedUri", "siteUri", "livemark"];
     var string = (this.props.type ? this.props.type + " " : "") +
       "(" +
       (function() {
         var ret = [];
         for (var i in props) {
@@ -104,79 +103,71 @@ PlacesItem.prototype = {
             ret.push(props[i] + ": " + that.props[props[i]])
           }
         }
         return ret;
       })().join(", ") + ")";
     return string;
   },
 
-  GetSyncId() {
-    let guid = Async.promiseSpinningly(PlacesUtils.promiseItemGuid(this.props.item_id));
-    return PlacesSyncUtils.bookmarks.guidToSyncId(guid);
-  },
-
   /**
-   * GetPlacesNodeId
+   * GetPlacesChildGuid
    *
-   * Finds the id of the an item with the specified properties in the places
-   * database.
+   * Finds the guid of the an item with the specified properties in the places
+   * database under the specified parent.
    *
-   * @param folder The id of the folder to search
+   * @param folder The guid of the folder to search
    * @param type The type of the item to find, or null to match any item;
-   *        this is one of the values listed at
-   *        https://developer.mozilla.org/en/nsINavHistoryResultNode#Constants
+   *        this is one of the PlacesUtils.bookmarks.TYPE_* values
    * @param title The title of the item to find, or null to match any title
    * @param uri The uri of the item to find, or null to match any uri
    *
-   * @return the node id if the item was found, otherwise -1
+   * @return the node id if the item was found, otherwise null
    */
-  GetPlacesNodeId(folder, type, title, uri) {
-    let node_id = -1;
-
-    let options = PlacesUtils.history.getNewQueryOptions();
-    let query = PlacesUtils.history.getNewQuery();
-    query.setFolders([folder], 1);
-    let result = PlacesUtils.history.executeQuery(query, options);
-    let rootNode = result.root;
-    rootNode.containerOpen = true;
-
-    for (let j = 0; j < rootNode.childCount; j++) {
-      let node = rootNode.getChild(j);
+  async GetPlacesChildGuid(folder, type, title, uri) {
+    let children = (await PlacesUtils.promiseBookmarksTree(folder)).children;
+    if (!children) {
+      return null;
+    }
+    let guid = null;
+    for (let node of children) {
       if (node.title == title) {
-        if (type == null || type == undefined || node.type == type)
-          if (uri == undefined || uri == null || node.uri.spec == uri.spec)
-            node_id = node.itemId;
+        let nodeType = this._typeMap.get(node.type);
+        if (type == null || type == undefined || nodeType == type)
+          if (uri == undefined || uri == null || node.uri.spec == uri.spec) {
+            // Note that this is suspect as we return the *last* matching
+            // child, which some tests rely on (ie, an early-return here causes
+            // at least 1 test to fail). But that's a yak for another day.
+            guid = node.guid;
+          }
       }
     }
-    rootNode.containerOpen = false;
-
-    return node_id;
+    return guid;
   },
 
   /**
    * IsAdjacentTo
    *
    * Determines if this object is immediately adjacent to another.
    *
    * @param itemName The name of the other object; this may be any kind of
    *        places item
    * @param relativePos The relative position of the other object.  If -1,
    *        it means the other object should precede this one, if +1,
    *        the other object should come after this one
    * @return true if this object is immediately adjacent to the other object,
    *         otherwise false
    */
-  IsAdjacentTo(itemName, relativePos) {
-    Logger.AssertTrue(this.props.folder_id != -1 && this.props.item_id != -1,
-      "Either folder_id or item_id was invalid");
-    let other_id = this.GetPlacesNodeId(this.props.folder_id, null, itemName);
-    Logger.AssertTrue(other_id != -1, "item " + itemName + " not found");
-    let other_pos = PlacesUtils.bookmarks.getItemIndex(other_id);
-    let this_pos = PlacesUtils.bookmarks.getItemIndex(this.props.item_id);
+  async IsAdjacentTo(itemName, relativePos) {
+    Logger.AssertTrue(this.props.folder_id != -1 && this.props.guid != null,
+      "Either folder_id or guid was invalid");
+    let otherGuid = await this.GetPlacesChildGuid(this.props.parentGuid, null, itemName);
+    Logger.AssertTrue(otherGuid, "item " + itemName + " not found");
+    let other_pos = (await PlacesUtils.bookmarks.fetch(otherGuid)).index;
+    let this_pos = (await PlacesUtils.bookmarks.fetch(this.props.guid)).index;
     if (other_pos + relativePos != this_pos) {
       Logger.logPotentialError("Invalid position - " +
        (this.props.title ? this.props.title : this.props.folder) +
       " not " + (relativePos == 1 ? "after " : "before ") + itemName +
       " for " + this.toString());
       return false;
     }
     return true;
@@ -184,118 +175,117 @@ PlacesItem.prototype = {
 
   /**
    * GetItemIndex
    *
    * Gets the item index for this places item.
    *
    * @return the item index, or -1 if there's an error
    */
-  GetItemIndex() {
-    if (this.props.item_id == -1)
+  async GetItemIndex() {
+    if (this.props.guid == null)
       return -1;
-    return PlacesUtils.bookmarks.getItemIndex(this.props.item_id);
+    return (await PlacesUtils.bookmarks.fetch(this.props.guid)).index;
   },
 
   /**
    * GetFolder
    *
-   * Gets the folder id for the specified bookmark folder
+   * Gets the folder guid for the specified bookmark folder
    *
    * @param location The full path of the folder, which must begin
    *        with one of the bookmark root folders
-   * @return the folder id if the folder is found, otherwise -1
+   * @return the folder guid if the folder is found, otherwise null
    */
-  GetFolder(location) {
+  async GetFolder(location) {
     let folder_parts = location.split("/");
     if (!(folder_parts[0] in this._bookmarkFolders)) {
-      return -1;
+      return null;
     }
-    let folder_id = PlacesUtils.bookmarks[this._bookmarkFolders[folder_parts[0]]];
+    let folderGuid = this._bookmarkFolders[folder_parts[0]];
     for (let i = 1; i < folder_parts.length; i++) {
-      let subfolder_id = this.GetPlacesNodeId(
-        folder_id,
-        Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
+      let guid = await this.GetPlacesChildGuid(
+        folderGuid,
+        PlacesUtils.bookmarks.TYPE_FOLDER,
         folder_parts[i]);
-      if (subfolder_id == -1) {
-        return -1;
+      if (guid == null) {
+        return null;
       }
-      folder_id = subfolder_id;
+      folderGuid = guid;
     }
-    return folder_id;
+    return folderGuid;
   },
 
   /**
    * CreateFolder
    *
    * Creates a bookmark folder.
    *
    * @param location The full path of the folder, which must begin
    *        with one of the bookmark root folders
    * @return the folder id if the folder was created, otherwise -1
    */
-  CreateFolder(location) {
+  async CreateFolder(location) {
     let folder_parts = location.split("/");
     if (!(folder_parts[0] in this._bookmarkFolders)) {
       return -1;
     }
-    let folder_id = PlacesUtils.bookmarks[this._bookmarkFolders[folder_parts[0]]];
+    let folderGuid = this._bookmarkFolders[folder_parts[0]];
     for (let i = 1; i < folder_parts.length; i++) {
-      let subfolder_id = this.GetPlacesNodeId(
-        folder_id,
-        Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
-        folder_parts[i]);
-      if (subfolder_id == -1) {
-        folder_id = PlacesUtils.bookmarks.createFolder(folder_id,
-                                                 folder_parts[i], -1);
+      let subfolderGuid = await this.GetPlacesChildGuid(
+        folderGuid,
+        PlacesUtils.bookmarks.TYPE_FOLDER,
+        folder_parts[i]
+      );
+      if (subfolderGuid == null) {
+        let {guid} = await PlacesUtils.bookmarks.insert({parentGuid: folderGuid,
+                                                         name: folder_parts[i],
+                                                         type: PlacesUtils.bookmarks.TYPE_FOLDER});
+        folderGuid = guid;
       } else {
-        folder_id = subfolder_id;
+        folderGuid = subfolderGuid;
       }
     }
-    return folder_id;
+    return folderGuid;
   },
 
   /**
    * GetOrCreateFolder
    *
    * Locates the specified folder; if not found it is created.
    *
    * @param location The full path of the folder, which must begin
    *        with one of the bookmark root folders
    * @return the folder id if the folder was found or created, otherwise -1
    */
-  GetOrCreateFolder(location) {
-    let folder_id = this.GetFolder(location);
-    if (folder_id == -1)
-      folder_id = this.CreateFolder(location);
-    return folder_id;
+  async GetOrCreateFolder(location) {
+    let parentGuid = await this.GetFolder(location);
+    if (parentGuid == null)
+      parentGuid = await this.CreateFolder(location);
+    return parentGuid;
   },
 
   /**
    * CheckDescription
    *
    * Compares the description of this places item with an expected
    * description.
    *
    * @param expectedDescription The description this places item is
    *        expected to have
    * @return true if the actual and expected descriptions match, or if
    *         there is no expected description; otherwise false
    */
-  CheckDescription(expectedDescription) {
+  async CheckDescription(expectedDescription) {
     if (expectedDescription != null) {
-      let description = "";
-      if (PlacesUtils.annotations.itemHasAnnotation(this.props.item_id,
-          "bookmarkProperties/description")) {
-        description = PlacesUtils.annotations.getItemAnnotation(
-          this.props.item_id, "bookmarkProperties/description");
-      }
-      if (description != expectedDescription) {
+      // Use PlacesSyncUtils as it gives us the description.
+      let info = await PlacesSyncUtils.bookmarks.fetch(this.props.guid);
+      if (info.description != expectedDescription) {
         Logger.logPotentialError("Invalid description, expected: " +
-          expectedDescription + ", actual: " + description + " for " +
+          expectedDescription + ", actual: " + info.description + " for " +
           this.toString());
         return false;
       }
     }
     return true;
   },
 
   /**
@@ -306,25 +296,26 @@ PlacesItem.prototype = {
    * @param before The name of the places item that this item should be
             before, or null if this check should be skipped
    * @param after The name of the places item that this item should be
             after, or null if this check should be skipped
    * @param last_item_pos The index of the places item above this one,
    *        or null if this check should be skipped
    * @return true if this item is in the correct position, otherwise false
    */
-  CheckPosition(before, after, last_item_pos) {
+  async CheckPosition(before, after, last_item_pos) {
     if (after)
-      if (!this.IsAdjacentTo(after, 1)) return false;
+      if (!(await this.IsAdjacentTo(after, 1))) return false;
     if (before)
-      if (!this.IsAdjacentTo(before, -1)) return false;
+      if (!(await this.IsAdjacentTo(before, -1))) return false;
     if (last_item_pos != null && last_item_pos > -1) {
-      if (this.GetItemIndex() != last_item_pos + 1) {
+      let index = await this.GetItemIndex();
+      if (index != last_item_pos + 1) {
         Logger.logPotentialError("Item not found at the expected index, got " +
-          this.GetItemIndex() + ", expected " + (last_item_pos + 1) + " for " +
+          index + ", expected " + (last_item_pos + 1) + " for " +
           this.toString());
         return false;
       }
     }
     return true;
   },
 
   /**
@@ -332,85 +323,95 @@ PlacesItem.prototype = {
    *
    * Moves this places item to a different folder.
    *
    * @param location The full path of the folder to which to move this
    *        places item, which must begin with one of the bookmark root
    *        folders; if null, no changes are made
    * @return nothing if successful, otherwise an exception is thrown
    */
-  SetLocation(location) {
+  async SetLocation(location) {
     if (location != null) {
-      let newfolder_id = this.GetOrCreateFolder(location);
-      Logger.AssertTrue(newfolder_id != -1, "Location " + location +
+      let newfolderGuid = await this.GetOrCreateFolder(location);
+      Logger.AssertTrue(newfolderGuid, "Location " + location +
                         " doesn't exist; can't change item's location");
-      PlacesUtils.bookmarks.moveItem(this.props.item_id, newfolder_id, -1);
-      this.props.folder_id = newfolder_id;
+      await PlacesUtils.bookmarks.update({
+        guid: this.props.guid,
+        parentGuid: newfolderGuid,
+        index: PlacesUtils.bookmarks.DEFAULT_INDEX,
+      });
+      this.props.parentGuid = newfolderGuid;
     }
   },
 
   /**
    * SetDescription
    *
    * Updates the description for this places item.
    *
    * @param description The new description to set; if null, no changes are
    *        made
    * @return nothing
    */
-  SetDescription(description) {
+  async SetDescription(description) {
+    let itemId = await PlacesUtils.promiseItemId(this.props.guid);
+
     if (description != null) {
       if (description != "")
-        PlacesUtils.annotations.setItemAnnotation(this.props.item_id,
+        PlacesUtils.annotations.setItemAnnotation(itemId,
                                       "bookmarkProperties/description",
                                       description,
                                       0,
                                       PlacesUtils.annotations.EXPIRE_NEVER);
       else
-        PlacesUtils.annotations.removeItemAnnotation(this.props.item_id,
+        PlacesUtils.annotations.removeItemAnnotation(itemId,
                                          "bookmarkProperties/description");
     }
   },
 
   /**
    * SetPosition
    *
    * Updates the position of this places item within this item's current
    * folder.  Use SetLocation to change folders.
    *
    * @param position The new index this item should be moved to; if null,
    *        no changes are made; if -1, this item is moved to the bottom of
-   *        the current folder
+   *        the current folder. Otherwise, must be a string which is the
+   *        title of an existing item in the folder, who's current position
+   *        is used as the index.
    * @return nothing if successful, otherwise an exception is thrown
    */
-  SetPosition(position) {
-    if (position != null) {
-      let newposition = -1;
-      if (position != -1) {
-        newposition = this.GetPlacesNodeId(this.props.folder_id,
-                                           null, position);
-        Logger.AssertTrue(newposition != -1, "position " + position +
-                          " is invalid; unable to change position");
-        newposition = PlacesUtils.bookmarks.getItemIndex(newposition);
+  async SetPosition(position) {
+    if (position == null) {
+      return;
+    }
+    let index = -1;
+    if (position != -1) {
+      let existingGuid = await this.GetPlacesChildGuid(this.props.parentGuid,
+                                                       null, position);
+      if (existingGuid) {
+        index = (await PlacesUtils.bookmarks.fetch(existingGuid)).index;
       }
-      PlacesUtils.bookmarks.moveItem(this.props.item_id,
-                               this.props.folder_id, newposition);
+      Logger.AssertTrue(index != -1, "position " + position +
+                        " is invalid; unable to change position");
     }
+    await PlacesUtils.bookmarks.update({guid: this.props.guid, index});
   },
 
   /**
    * Update the title of this places item
    *
    * @param title The new title to set for this item; if null, no changes
    *        are made
    * @return nothing
    */
-  SetTitle(title) {
+  async SetTitle(title) {
     if (title != null) {
-      PlacesUtils.bookmarks.setItemTitle(this.props.item_id, title);
+      await PlacesUtils.bookmarks.update({guid: this.props.guid, title});
     }
   },
 };
 
 /**
  * Bookmark class constructor.  Initializes instance properties.
  */
 function Bookmark(props) {
@@ -428,81 +429,63 @@ Bookmark.prototype = {
    * SetKeyword
    *
    * Update this bookmark's keyword.
    *
    * @param keyword The keyword to set for this bookmark; if null, no
    *        changes are made
    * @return nothing
    */
-  SetKeyword(keyword) {
+  async SetKeyword(keyword) {
     if (keyword != null) {
       // Mirror logic from PlacesSyncUtils's updateBookmarkMetadata
-      let entry = Async.promiseSpinningly(PlacesUtils.keywords.fetch({
-        url: this.props.uri,
-      }));
+      let entry = await PlacesUtils.keywords.fetch({url: this.props.uri});
       if (entry) {
-        Async.promiseSpinningly(PlacesUtils.keywords.remove(entry));
+        await PlacesUtils.keywords.remove(entry);
       }
-      Async.promiseSpinningly(PlacesUtils.keywords.insert({
-        keyword,
-        url: this.props.uri
-      }));
+      await PlacesUtils.keywords.insert({keyword, url: this.props.uri});
     }
   },
 
   /**
    * SetLoadInSidebar
    *
    * Updates this bookmark's loadInSidebar property.
    *
    * @param loadInSidebar if true, the loadInSidebar property will be set,
    *        if false, it will be cleared, and any other value will result
    *        in no change
    * @return nothing
    */
-  SetLoadInSidebar(loadInSidebar) {
+  async SetLoadInSidebar(loadInSidebar) {
+    let itemId = await PlacesUtils.promiseItemId(this.props.guid);
     if (loadInSidebar == true)
-      PlacesUtils.annotations.setItemAnnotation(this.props.item_id,
+      PlacesUtils.annotations.setItemAnnotation(itemId,
                                     "bookmarkProperties/loadInSidebar",
                                     true,
                                     0,
                                     PlacesUtils.annotations.EXPIRE_NEVER);
     else if (loadInSidebar == false)
-      PlacesUtils.annotations.removeItemAnnotation(this.props.item_id,
+      PlacesUtils.annotations.removeItemAnnotation(itemId,
                                        "bookmarkProperties/loadInSidebar");
   },
 
   /**
-   * SetTitle
-   *
-   * Updates this bookmark's title.
-   *
-   * @param title The new title to set for this boomark; if null, no changes
-   *        are made
-   * @return nothing
-   */
-  SetTitle(title) {
-    if (title)
-      PlacesUtils.bookmarks.setItemTitle(this.props.item_id, title);
-  },
-
-  /**
    * SetUri
    *
    * Updates this bookmark's URI.
    *
    * @param uri The new URI to set for this boomark; if null, no changes
    *        are made
    * @return nothing
    */
-  SetUri(uri) {
+  async SetUri(uri) {
     if (uri) {
-      let newURI = Services.io.newURI(uri);
-      PlacesUtils.bookmarks.changeBookmarkURI(this.props.item_id, newURI);
+      let url = Services.io.newURI(uri);
+      await PlacesUtils.bookmarks.update({guid: this.props.guid, url})
     }
   },
 
   /**
    * SetTags
    *
    * Updates this bookmark's tags.
    *
@@ -523,138 +506,138 @@ Bookmark.prototype = {
 
   /**
    * Create
    *
    * Creates the bookmark described by this object's properties.
    *
    * @return the id of the created bookmark
    */
-  Create() {
-    this.props.folder_id = this.GetOrCreateFolder(this.props.location);
-    Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
+  async Create() {
+    this.props.parentGuid = await this.GetOrCreateFolder(this.props.location);
+    Logger.AssertTrue(this.props.parentGuid, "Unable to create " +
       "bookmark, error creating folder " + this.props.location);
     let bookmarkURI = Services.io.newURI(this.props.uri);
-    this.props.item_id = PlacesUtils.bookmarks.insertBookmark(this.props.folder_id,
-                                                        bookmarkURI,
-                                                        -1,
-                                                        this.props.title);
-    this.SetKeyword(this.props.keyword);
-    this.SetDescription(this.props.description);
-    this.SetLoadInSidebar(this.props.loadInSidebar);
-    this.SetTags(this.props.tags);
-    return this.props.item_id;
+    let {guid} = await PlacesUtils.bookmarks.insert({parentGuid: this.props.parentGuid,
+                                                     url: bookmarkURI,
+                                                     title: this.props.title});
+    this.props.guid = guid;
+    await this.SetKeyword(this.props.keyword);
+    await this.SetDescription(this.props.description);
+    await this.SetLoadInSidebar(this.props.loadInSidebar);
+    await this.SetTags(this.props.tags);
+    return this.props.guid;
   },
 
   /**
    * Update
    *
    * Updates this bookmark's properties according the properties on this
    * object's 'updateProps' property.
    *
    * @return nothing
    */
-  Update() {
-    Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
-      "Invalid item_id during Remove");
-    this.SetDescription(this.updateProps.description);
-    this.SetLoadInSidebar(this.updateProps.loadInSidebar);
-    this.SetTitle(this.updateProps.title);
-    this.SetUri(this.updateProps.uri);
-    this.SetKeyword(this.updateProps.keyword);
-    this.SetTags(this.updateProps.tags);
-    this.SetLocation(this.updateProps.location);
-    this.SetPosition(this.updateProps.position);
+  async Update() {
+    Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+    await this.SetDescription(this.updateProps.description);
+    await this.SetLoadInSidebar(this.updateProps.loadInSidebar);
+    await this.SetTitle(this.updateProps.title);
+    await this.SetUri(this.updateProps.uri);
+    await this.SetKeyword(this.updateProps.keyword);
+    await this.SetTags(this.updateProps.tags);
+    await this.SetLocation(this.updateProps.location);
+    await this.SetPosition(this.updateProps.position);
   },
 
   /**
    * Find
    *
    * Locates the bookmark which corresponds to this object's properties.
    *
-   * @return the bookmark id if the bookmark was found, otherwise -1
+   * @return the bookmark guid if the bookmark was found, otherwise null
    */
-  Find() {
-    this.props.folder_id = this.GetFolder(this.props.location);
-    if (this.props.folder_id == -1) {
+  async Find() {
+    this.props.parentGuid = await this.GetFolder(this.props.location);
+
+    if (this.props.parentGuid == null) {
       Logger.logError("Unable to find folder " + this.props.location);
-      return -1;
+      return null;
     }
     let bookmarkTitle = this.props.title;
-    this.props.item_id = this.GetPlacesNodeId(this.props.folder_id,
-                                              null,
-                                              bookmarkTitle,
-                                              this.props.uri);
+    this.props.guid = await this.GetPlacesChildGuid(this.props.parentGuid,
+                                                    null,
+                                                    bookmarkTitle,
+                                                    this.props.uri);
 
-    if (this.props.item_id == -1) {
+    if (!this.props.guid) {
       Logger.logPotentialError(this.toString() + " not found");
-      return -1;
+      return null;
     }
-    if (!this.CheckDescription(this.props.description))
-      return -1;
+    if (!(await this.CheckDescription(this.props.description))) {
+      return null;
+    }
     if (this.props.keyword != null) {
-      let { keyword } = Async.promiseSpinningly(
-        PlacesSyncUtils.bookmarks.fetch(this.GetSyncId()));
+      let {keyword} = await PlacesSyncUtils.bookmarks.fetch(this.props.guid);
       if (keyword != this.props.keyword) {
         Logger.logPotentialError("Incorrect keyword - expected: " +
           this.props.keyword + ", actual: " + keyword +
           " for " + this.toString());
-        return -1;
+        return null;
       }
     }
+    let itemId = await PlacesUtils.promiseItemId(this.props.guid);
     let loadInSidebar = PlacesUtils.annotations.itemHasAnnotation(
-      this.props.item_id,
+      itemId,
       "bookmarkProperties/loadInSidebar");
     if (loadInSidebar)
       loadInSidebar = PlacesUtils.annotations.getItemAnnotation(
-        this.props.item_id,
+        itemId,
         "bookmarkProperties/loadInSidebar");
     if (this.props.loadInSidebar != null &&
         loadInSidebar != this.props.loadInSidebar) {
       Logger.logPotentialError("Incorrect loadInSidebar setting - expected: " +
         this.props.loadInSidebar + ", actual: " + loadInSidebar +
         " for " + this.toString());
-      return -1;
+      return null;
     }
     if (this.props.tags != null) {
       try {
         let URI = Services.io.newURI(this.props.uri);
         let tags = PlacesUtils.tagging.getTagsForURI(URI, {});
         tags.sort();
         this.props.tags.sort();
         if (JSON.stringify(tags) != JSON.stringify(this.props.tags)) {
           Logger.logPotentialError("Wrong tags - expected: " +
             JSON.stringify(this.props.tags) + ", actual: " +
             JSON.stringify(tags) + " for " + this.toString());
-          return -1;
+          return null;
         }
       } catch (e) {
         Logger.logPotentialError("error processing tags " + e);
-        return -1;
+        return null;
       }
     }
-    if (!this.CheckPosition(this.props.before,
-                            this.props.after,
-                            this.props.last_item_pos))
-      return -1;
-    return this.props.item_id;
+    if (!(await this.CheckPosition(this.props.before,
+                                 this.props.after,
+                                 this.props.last_item_pos)))
+      return null;
+    return this.props.guid;
   },
 
   /**
    * Remove
    *
    * Removes this bookmark.  The bookmark should have been located previously
    * by a call to Find.
    *
    * @return nothing
    */
-  Remove() {
-    Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
-      "Invalid item_id during Remove");
-    PlacesUtils.bookmarks.removeItem(this.props.item_id);
+  async Remove() {
+    Logger.AssertTrue(this.props.guid, "Invalid guid during Remove");
+    await PlacesUtils.bookmarks.remove(this.props.guid);
   },
 };
 
 extend(Bookmark, PlacesItem);
 
 /**
  * BookmarkFolder class constructor. Initializes instance properties.
  */
@@ -669,84 +652,89 @@ function BookmarkFolder(props) {
 BookmarkFolder.prototype = {
   /**
    * Create
    *
    * Creates the bookmark folder described by this object's properties.
    *
    * @return the id of the created bookmark folder
    */
-  Create() {
-    this.props.folder_id = this.GetOrCreateFolder(this.props.location);
-    Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
+  async Create() {
+    this.props.parentGuid = await this.GetOrCreateFolder(this.props.location);
+    Logger.AssertTrue(this.props.parentGuid, "Unable to create " +
       "folder, error creating parent folder " + this.props.location);
-    this.props.item_id = PlacesUtils.bookmarks.createFolder(this.props.folder_id,
-                                                      this.props.folder,
-                                                      -1);
-    this.SetDescription(this.props.description);
-    return this.props.folder_id;
+    let {guid} = await PlacesUtils.bookmarks.insert({parentGuid: this.props.parentGuid,
+                                                     title: this.props.folder,
+                                                     index: PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                                     type: PlacesUtils.bookmarks.TYPE_FOLDER,
+                                                     });
+    this.props.guid = guid;
+    await this.SetDescription(this.props.description);
+    return this.props.parentGuid;
   },
 
   /**
    * Find
    *
    * Locates the bookmark folder which corresponds to this object's
    * properties.
    *
-   * @return the folder id if the folder was found, otherwise -1
+   * @return the folder guid if the folder was found, otherwise null
    */
-  Find() {
-    this.props.folder_id = this.GetFolder(this.props.location);
-    if (this.props.folder_id == -1) {
+  async Find() {
+    this.props.parentGuid = await this.GetFolder(this.props.location);
+    if (this.props.parentGuid == null) {
       Logger.logError("Unable to find folder " + this.props.location);
-      return -1;
+      return null;
     }
-    this.props.item_id = this.GetPlacesNodeId(
-                              this.props.folder_id,
-                              Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
+    this.props.guid = await this.GetPlacesChildGuid(
+                              this.props.parentGuid,
+                              PlacesUtils.bookmarks.TYPE_FOLDER,
                               this.props.folder);
-    if (!this.CheckDescription(this.props.description))
-      return -1;
-    if (!this.CheckPosition(this.props.before,
-                            this.props.after,
-                            this.props.last_item_pos))
-      return -1;
-    return this.props.item_id;
+    if (this.props.guid == null) {
+      return null;
+    }
+    if (!(await this.CheckDescription(this.props.description))) {
+      return null;
+    }
+    if (!(await this.CheckPosition(this.props.before,
+                                   this.props.after,
+                                   this.props.last_item_pos))) {
+      return null;
+    }
+    return this.props.guid;
   },
 
   /**
    * Remove
    *
    * Removes this folder.  The folder should have been located previously
    * by a call to Find.
    *
    * @return nothing
    */
-  Remove() {
-    Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
-      "Invalid item_id during Remove");
-    PlacesUtils.bookmarks.removeFolderChildren(this.props.item_id);
-    PlacesUtils.bookmarks.removeItem(this.props.item_id);
+  async Remove() {
+    Logger.AssertTrue(this.props.guid, "Invalid guid during Remove");
+    await PlacesUtils.bookmarks.remove(this.props.guid);
   },
 
   /**
    * Update
    *
    * Updates this bookmark's properties according the properties on this
    * object's 'updateProps' property.
    *
    * @return nothing
    */
-  Update() {
-    Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
-      "Invalid item_id during Update");
-    this.SetLocation(this.updateProps.location);
-    this.SetPosition(this.updateProps.position);
-    this.SetTitle(this.updateProps.folder);
-    this.SetDescription(this.updateProps.description);
+  async Update() {
+    Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+    await this.SetLocation(this.updateProps.location);
+    await this.SetPosition(this.updateProps.position);
+    await this.SetTitle(this.updateProps.folder);
+    await this.SetDescription(this.updateProps.description);
   },
 };
 
 extend(BookmarkFolder, PlacesItem);
 
 /**
  * Livemark class constructor. Initialzes instance properties.
  */
@@ -761,129 +749,120 @@ function Livemark(props) {
 Livemark.prototype = {
   /**
    * Create
    *
    * Creates the livemark described by this object's properties.
    *
    * @return the id of the created livemark
    */
-  Create() {
-    this.props.folder_id = this.GetOrCreateFolder(this.props.location);
-    Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
+  async Create() {
+    this.props.parentGuid = await this.GetOrCreateFolder(this.props.location);
+    Logger.AssertTrue(this.props.parentGuid, "Unable to create " +
       "folder, error creating parent folder " + this.props.location);
     let siteURI = null;
     if (this.props.siteUri != null)
       siteURI = Services.io.newURI(this.props.siteUri);
-    let livemarkObj = {parentId: this.props.folder_id,
+    let livemarkObj = {parentGuid: this.props.parentGuid,
                        title: this.props.livemark,
                        siteURI,
                        feedURI: Services.io.newURI(this.props.feedUri),
                        index: PlacesUtils.bookmarks.DEFAULT_INDEX};
 
-    // Until this can handle asynchronous creation, we need to spin.
-    let spinningCb = Async.makeSpinningCallback();
-
-    PlacesUtils.livemarks.addLivemark(livemarkObj).then(
-      aLivemark => { spinningCb(null, [Components.results.NS_OK, aLivemark]) },
-      () => { spinningCb(null, [Components.results.NS_ERROR_UNEXPECTED, null]) }
-    );
-
-    let [status, livemark] = spinningCb.wait();
-    if (!Components.isSuccessCode(status)) {
-      throw new Error(status);
-    }
-
-    this.props.item_id = livemark.id;
-    return this.props.item_id;
+    let livemark = await PlacesUtils.livemarks.addLivemark(livemarkObj);
+    this.props.guid = livemark.guid;
+    return this.props.guid;
   },
 
   /**
    * Find
    *
    * Locates the livemark which corresponds to this object's
    * properties.
    *
-   * @return the item id if the livemark was found, otherwise -1
+   * @return the item guid if the livemark was found, otherwise null
    */
-  Find() {
-    this.props.folder_id = this.GetFolder(this.props.location);
-    if (this.props.folder_id == -1) {
+  async Find() {
+    this.props.parentGuid = await this.GetFolder(this.props.location);
+    if (this.props.parentGuid == null) {
       Logger.logError("Unable to find folder " + this.props.location);
-      return -1;
+      return null;
     }
-    this.props.item_id = this.GetPlacesNodeId(
-                              this.props.folder_id,
-                              Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
+    this.props.guid = await this.GetPlacesChildGuid(
+                              this.props.parentGuid,
+                              PlacesUtils.bookmarks.TYPE_FOLDER,
                               this.props.livemark);
+    if (!this.props.guid) {
+      Logger.logPotentialError("can't find livemark for " + this.toString());
+      return null;
+    }
+    let itemId = await PlacesUtils.promiseItemId(this.props.guid);
     if (!PlacesUtils.annotations
-                    .itemHasAnnotation(this.props.item_id, PlacesUtils.LMANNO_FEEDURI)) {
+                    .itemHasAnnotation(itemId, PlacesUtils.LMANNO_FEEDURI)) {
       Logger.logPotentialError("livemark folder found, but it's just a regular folder, for " +
         this.toString());
-      this.props.item_id = -1;
-      return -1;
+      this.props.guid = null;
+      return null;
     }
     let feedURI = Services.io.newURI(this.props.feedUri);
     let lmFeedURISpec =
-      PlacesUtils.annotations.getItemAnnotation(this.props.item_id,
+      PlacesUtils.annotations.getItemAnnotation(itemId,
                                                 PlacesUtils.LMANNO_FEEDURI);
     if (feedURI.spec != lmFeedURISpec) {
       Logger.logPotentialError("livemark feed uri not correct, expected: " +
         this.props.feedUri + ", actual: " + lmFeedURISpec +
         " for " + this.toString());
-      return -1;
+      return null;
     }
     if (this.props.siteUri != null) {
       let siteURI = Services.io.newURI(this.props.siteUri);
       let lmSiteURISpec =
-        PlacesUtils.annotations.getItemAnnotation(this.props.item_id,
+        PlacesUtils.annotations.getItemAnnotation(itemId,
                                                   PlacesUtils.LMANNO_SITEURI);
       if (siteURI.spec != lmSiteURISpec) {
         Logger.logPotentialError("livemark site uri not correct, expected: " +
         this.props.siteUri + ", actual: " + lmSiteURISpec + " for " +
         this.toString());
-        return -1;
+        return null;
       }
     }
-    if (!this.CheckPosition(this.props.before,
-                            this.props.after,
-                            this.props.last_item_pos))
-      return -1;
-    return this.props.item_id;
+    if (!(await this.CheckPosition(this.props.before,
+                                   this.props.after,
+                                   this.props.last_item_pos)))
+      return null;
+    return this.props.guid;
   },
 
   /**
    * Update
    *
    * Updates this livemark's properties according the properties on this
    * object's 'updateProps' property.
    *
    * @return nothing
    */
-  Update() {
-    Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
-      "Invalid item_id during Update");
-    this.SetLocation(this.updateProps.location);
-    this.SetPosition(this.updateProps.position);
-    this.SetTitle(this.updateProps.livemark);
+  async Update() {
+    Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+    await this.SetLocation(this.updateProps.location);
+    await this.SetPosition(this.updateProps.position);
+    await this.SetTitle(this.updateProps.livemark);
     return true;
   },
 
   /**
    * Remove
    *
    * Removes this livemark.  The livemark should have been located previously
    * by a call to Find.
    *
    * @return nothing
    */
-  Remove() {
-    Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
-      "Invalid item_id during Remove");
-    PlacesUtils.bookmarks.removeItem(this.props.item_id);
+  async Remove() {
+    Logger.AssertTrue(this.props.guid, "Invalid guid during Remove");
+    await PlacesUtils.bookmarks.remove(this.props.guid);
   },
 };
 
 extend(Livemark, PlacesItem);
 
 /**
  * Separator class constructor. Initializes instance properties.
  */
@@ -898,95 +877,99 @@ function Separator(props) {
 Separator.prototype = {
   /**
    * Create
    *
    * Creates the bookmark separator described by this object's properties.
    *
    * @return the id of the created separator
    */
-  Create() {
-    this.props.folder_id = this.GetOrCreateFolder(this.props.location);
-    Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
+  async Create() {
+    this.props.parentGuid = await this.GetOrCreateFolder(this.props.location);
+    Logger.AssertTrue(this.props.parentGuid, "Unable to create " +
       "folder, error creating parent folder " + this.props.location);
-    this.props.item_id = PlacesUtils.bookmarks.insertSeparator(this.props.folder_id,
-                                                         -1);
-    return this.props.item_id;
+    let {guid} = await PlacesUtils.bookmarks.insert({
+      parentGuid: this.props.parentGuid,
+      type: PlacesUtils.bookmarks.TYPE_SEPARATOR
+    });
+    this.props.guid = guid;
+    return guid;
   },
 
   /**
    * Find
    *
    * Locates the bookmark separator which corresponds to this object's
    * properties.
    *
-   * @return the item id if the separator was found, otherwise -1
+   * @return the item guid if the separator was found, otherwise null
    */
-  Find() {
-    this.props.folder_id = this.GetFolder(this.props.location);
-    if (this.props.folder_id == -1) {
+  async Find() {
+    this.props.parentGuid = await this.GetFolder(this.props.location);
+    if (this.props.parentGuid == null) {
       Logger.logError("Unable to find folder " + this.props.location);
-      return -1;
+      return null;
     }
     if (this.props.before == null && this.props.last_item_pos == null) {
       Logger.logPotentialError("Separator requires 'before' attribute if it's the" +
         "first item in the list");
-      return -1;
+      return null;
     }
     let expected_pos = -1;
     if (this.props.before) {
-      let other_id = this.GetPlacesNodeId(this.props.folder_id,
-                                          null,
-                                          this.props.before);
-      if (other_id == -1) {
+      let otherGuid = this.GetPlacesChildGuid(this.props.parentGuid,
+                                              null,
+                                              this.props.before);
+      if (otherGuid == null) {
         Logger.logPotentialError("Can't find places item " + this.props.before +
           " for locating separator");
-        return -1;
+        return null;
       }
-      expected_pos = PlacesUtils.bookmarks.getItemIndex(other_id) - 1;
+      expected_pos = (await PlacesUtils.bookmarks.fetch(otherGuid)).index - 1;
     } else {
       expected_pos = this.props.last_item_pos + 1;
     }
-    this.props.item_id = PlacesUtils.bookmarks.getIdForItemAt(this.props.folder_id,
-                                                        expected_pos);
-    if (this.props.item_id == -1) {
+    // Note these are syncIDs instead of GUIDs, but that's ok here.
+    let children = await PlacesSyncUtils.bookmarks.fetchChildSyncIds(this.props.parentGuid);
+    this.props.guid = children[expected_pos];
+    if (this.props.guid == null) {
       Logger.logPotentialError("No separator found at position " + expected_pos);
-    } else if (PlacesUtils.bookmarks.getItemType(this.props.item_id) !=
-          PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-        Logger.logPotentialError("Places item at position " + expected_pos +
-          " is not a separator");
-        return -1;
-      }
-    return this.props.item_id;
+      return null;
+    }
+    let info = await PlacesUtils.bookmarks.fetch(this.props.guid);
+    if (info.type != PlacesUtils.bookmarks.TYPE_SEPARATOR) {
+      Logger.logPotentialError("Places item at position " + expected_pos +
+        " is not a separator");
+      return null;
+    }
+    return this.props.guid;
   },
 
   /**
    * Update
    *
    * Updates this separator's properties according the properties on this
    * object's 'updateProps' property.
    *
    * @return nothing
    */
-  Update() {
-    Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
-      "Invalid item_id during Update");
-    this.SetLocation(this.updateProps.location);
-    this.SetPosition(this.updateProps.position);
+  async Update() {
+    Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+    await this.SetLocation(this.updateProps.location);
+    await this.SetPosition(this.updateProps.position);
     return true;
   },
 
   /**
    * Remove
    *
    * Removes this separator.  The separator should have been located
    * previously by a call to Find.
    *
    * @return nothing
    */
-  Remove() {
-    Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
-      "Invalid item_id during Update");
-    PlacesUtils.bookmarks.removeItem(this.props.item_id);
+  async Remove() {
+    Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+    await PlacesUtils.bookmarks.remove(this.props.guid);
   },
 };
 
 extend(Separator, PlacesItem);
--- a/services/sync/tps/extensions/tps/resource/tps.jsm
+++ b/services/sync/tps/extensions/tps/resource/tps.jsm
@@ -99,16 +99,17 @@ const OBSERVER_TOPICS = ["fxaccounts:onl
                          "weave:engine:stop-tracking",
                          "weave:service:login:error",
                          "weave:service:setup-complete",
                          "weave:service:sync:finish",
                          "weave:service:sync:delayed",
                          "weave:service:sync:error",
                          "weave:service:sync:start",
                          "weave:service:resyncs-finished",
+                         "places-browser-init-complete",
                         ];
 
 var TPS = {
   _currentAction: -1,
   _currentPhase: -1,
   _enabledEngines: null,
   _errors: 0,
   _isTracking: false,
@@ -127,16 +128,17 @@ var TPS = {
   _triggeredSync: false,
   _usSinceEpoch: 0,
   _requestedQuit: false,
   shouldValidateAddons: false,
   shouldValidateBookmarks: false,
   shouldValidatePasswords: false,
   shouldValidateForms: false,
   _windowsUpDeferred: PromiseUtils.defer(),
+  _placesInitDeferred: PromiseUtils.defer(),
 
   _init: function TPS__init() {
     this.delayAutoSync();
 
     OBSERVER_TOPICS.forEach(function(aTopic) {
       Services.obs.addObserver(this, aTopic, true);
     }, this);
 
@@ -177,16 +179,20 @@ var TPS = {
           Logger.close();
 
           break;
 
         case "sessionstore-windows-restored":
           this._windowsUpDeferred.resolve();
           break;
 
+        case "places-browser-init-complete":
+          this._placesInitDeferred.resolve();
+          break;
+
         case "weave:service:setup-complete":
           this._setupComplete = true;
 
           if (this._syncWipeAction) {
             Weave.Svc.Prefs.set("firstSync", this._syncWipeAction);
             this._syncWipeAction = null;
           }
 
@@ -500,81 +506,83 @@ var TPS = {
         default:
           throw new Error("Unknown action for add-on: " + action);
       }
     }
     Logger.logPass("executing action " + action.toUpperCase() +
                    " on addons");
   },
 
-  HandleBookmarks(bookmarks, action) {
+  async HandleBookmarks(bookmarks, action) {
+    // wait for default bookmarks to be created.
+    await this._placesInitDeferred.promise;
     this.shouldValidateBookmarks = true;
     try {
       let items = [];
       for (let folder in bookmarks) {
         let last_item_pos = -1;
         for (let bookmark of bookmarks[folder]) {
           Logger.clearPotentialError();
           let placesItem;
           bookmark.location = folder;
 
           if (last_item_pos != -1)
             bookmark.last_item_pos = last_item_pos;
-          let item_id = -1;
+          let itemGuid = null;
 
           if (action != ACTION_MODIFY && action != ACTION_DELETE)
             Logger.logInfo("executing action " + action.toUpperCase() +
                            " on bookmark " + JSON.stringify(bookmark));
 
           if ("uri" in bookmark)
             placesItem = new Bookmark(bookmark);
           else if ("folder" in bookmark)
             placesItem = new BookmarkFolder(bookmark);
           else if ("livemark" in bookmark)
             placesItem = new Livemark(bookmark);
           else if ("separator" in bookmark)
             placesItem = new Separator(bookmark);
 
           if (action == ACTION_ADD) {
-            item_id = placesItem.Create();
+            itemGuid = await placesItem.Create();
           } else {
-            item_id = placesItem.Find();
+            itemGuid = await placesItem.Find();
             if (action == ACTION_VERIFY_NOT) {
-              Logger.AssertTrue(item_id == -1,
+              Logger.AssertTrue(itemGuid == null,
                 "places item exists but it shouldn't: " +
                 JSON.stringify(bookmark));
             } else
-              Logger.AssertTrue(item_id != -1, "places item not found", true);
+              Logger.AssertTrue(itemGuid, "places item not found", true);
           }
 
-          last_item_pos = placesItem.GetItemIndex();
+          last_item_pos = await placesItem.GetItemIndex();
           items.push(placesItem);
         }
       }
 
       if (action == ACTION_DELETE || action == ACTION_MODIFY) {
         for (let item of items) {
           Logger.logInfo("executing action " + action.toUpperCase() +
                          " on bookmark " + JSON.stringify(item));
           switch (action) {
             case ACTION_DELETE:
-              item.Remove();
+              await item.Remove();
               break;
             case ACTION_MODIFY:
               if (item.updateProps != null)
-                item.Update();
+                await item.Update();
               break;
           }
         }
       }
 
       Logger.logPass("executing action " + action.toUpperCase() +
         " on bookmarks");
     } catch (e) {
-      DumpBookmarks();
+      await DumpBookmarks();
       throw (e);
     }
   },
 
   MozmillEndTestListener: function TPS__MozmillEndTestListener(obj) {
     Logger.logInfo("mozmill endTest: " + JSON.stringify(obj));
     if (obj.failed > 0) {
       this.DumpError("mozmill test failed, name: " + obj.name + ", reason: " + JSON.stringify(obj.fails));
@@ -1218,30 +1226,30 @@ var Addons = {
     TPS.HandleAddons(addons, ACTION_VERIFY_NOT);
   },
   skipValidation() {
     TPS.shouldValidateAddons = false;
   }
 };
 
 var Bookmarks = {
-  add: function Bookmarks__add(bookmarks) {
-    TPS.HandleBookmarks(bookmarks, ACTION_ADD);
+  async add(bookmarks) {
+    await TPS.HandleBookmarks(bookmarks, ACTION_ADD);
   },
-  modify: function Bookmarks__modify(bookmarks) {
-    TPS.HandleBookmarks(bookmarks, ACTION_MODIFY);
+  async modify(bookmarks) {
+    await TPS.HandleBookmarks(bookmarks, ACTION_MODIFY);
   },
-  delete: function Bookmarks__delete(bookmarks) {
-    TPS.HandleBookmarks(bookmarks, ACTION_DELETE);
+  async delete(bookmarks) {
+    await TPS.HandleBookmarks(bookmarks, ACTION_DELETE);
   },
-  verify: function Bookmarks__verify(bookmarks) {
-    TPS.HandleBookmarks(bookmarks, ACTION_VERIFY);
+  async verify(bookmarks) {
+    await TPS.HandleBookmarks(bookmarks, ACTION_VERIFY);
   },
-  verifyNot: function Bookmarks__verifyNot(bookmarks) {
-    TPS.HandleBookmarks(bookmarks, ACTION_VERIFY_NOT);
+  async verifyNot(bookmarks) {
+    await TPS.HandleBookmarks(bookmarks, ACTION_VERIFY_NOT);
   },
   skipValidation() {
     TPS.shouldValidateBookmarks = false;
   }
 };
 
 var Formdata = {
   add: function Formdata__add(formdata) {