function change(doc, options, callback) {
  if (doc[OBJECT_ID] !== '_root') {
    throw new TypeError('The first argument to Automerge.change must be the document root')
  }
  if (doc[CHANGE]) {
    throw new TypeError('Calls to Automerge.change cannot be nested')
  }
  if (typeof options === 'function' && callback === undefined) {
    [options, callback] = [callback, options]
  }
  if (typeof options === 'string') {
    options = {message: options}
  }
  if (options !== undefined && !isObject(options)) {
    throw new TypeError('Unsupported type of options')
  }

  const actorId = getActorId(doc)
  if (!actorId) {
    throw new Error('Actor ID must be initialized with setActorId() before making a change')
  }
  const context = new Context(doc, actorId)
  callback(rootObjectProxy(context))

  if (Object.keys(context.updated).length === 0) {
    // If the callback didn't change anything, return the original document object unchanged
    return [doc, null]
  } else {
    return makeChange(doc, context, options)
  }
}
Changes a document `doc` according to actions taken by the local user.
`options` is an object that can contain the following properties:
 - `message`: an optional descriptive string that is attached to the change.
If `options` is a string, it is treated as `message`.

The actual change is made within the callback function `callback`, which is
given a mutable version of the document as argument. Returns a two-element
array `[doc, request]` where `doc` is the updated document, and `request`
is the change request to send to the backend. If nothing was actually
changed, returns the original `doc` and a `null` change request.