applyOp(op) {
    if (!this.metadata[op.obj]) throw new RangeError(`Object does not exist: ${op.obj}`)
    if (op.action === 'makeMap') {
      this.byObjId[op.opId] = {}
      this.metadata[op.opId] = {}
    } else if (op.action === 'makeList') {
      this.byObjId[op.opId] = []
      this.metadata[op.opId] = []
    } else if (op.action !== 'set' && op.action !== 'del') {
      throw new RangeError(`Unsupported operation type: ${op.action}`)
    }

    if (Array.isArray(this.metadata[op.obj])) {
      if (op.insert) this.applyListInsert(op); else this.applyListUpdate(op)
    } else if (!this.metadata[op.obj][op.key] || this.compareOpIds(this.metadata[op.obj][op.key], op.opId)) {
      this.metadata[op.obj][op.key] = op.opId
      if (op.action === 'del') {
        delete this.byObjId[op.obj][op.key]
      } else if (op.action.startsWith('make')) {
        this.byObjId[op.obj][op.key] = this.byObjId[op.opId]
      } else {
        this.byObjId[op.obj][op.key] = op.value
      }
    }
  }
Updates the document state with one of the operations from a change.